diff --git a/.github/workflows/fuzz-testing.yml b/.github/workflows/fuzz-testing.yml index f33ece21dc..c9327b6dd4 100644 --- a/.github/workflows/fuzz-testing.yml +++ b/.github/workflows/fuzz-testing.yml @@ -59,6 +59,17 @@ jobs: run: | ./gradlew :rulesengine:test --tests "*FuzzTest*" -Djazzer.max_duration=1h --stacktrace + - name: Run HPACK fuzz tests + env: + JAZZER_FUZZ: "1" + run: | + ./gradlew :http:http-hpack:test --tests "*FuzzTest*" -Djazzer.max_duration=1h --stacktrace + + - name: Run HTTP client fuzz tests + env: + JAZZER_FUZZ: "1" + run: | + ./gradlew :http:http-client:test --tests "*FuzzTest*" -Djazzer.max_duration=1h --stacktrace - name: Save fuzz corpus cache uses: actions/cache/save@v6 if: always() diff --git a/.gitignore b/.gitignore index 9c2545a430..bfd8cc5d5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Ignore Gradle project-specific cache directory .gradle +.tool-versions + # Ignore kotlin cache dir .kotlin @@ -28,3 +30,5 @@ mise.toml .claude/settings.local.json **/bin + +benchmarks/e2e-benchmarks/profiles diff --git a/benchmarks/e2e-benchmarks/README.md b/benchmarks/e2e-benchmarks/README.md index a7ddcf97f3..5e0630f62c 100644 --- a/benchmarks/e2e-benchmarks/README.md +++ b/benchmarks/e2e-benchmarks/README.md @@ -1,8 +1,6 @@ # smithy-java end-to-end benchmark runner -A workload-driven runner that exercises the smithy-java SDK against live AWS -services. It implements the same workload spec as the Java SDK v2 reference -runner so results are directly comparable across SDKs. +A small fixed-workload runner that exercises the smithy-java SDK against live AWS services. ## Scope @@ -13,20 +11,13 @@ runner so results are directly comparable across SDKs. | S3 | PutObject | Throughput| | S3 | GetObject | Throughput| -Only the **synchronous** client mode is supported. smithy-java does not -generate async clients today, so a `--client async` argument is accepted but -prints a warning and proceeds with the sync client. Throughput tests still -push the SDK through a thread pool, which is the SDK's idiomatic concurrency -mechanism. - ## Build ```bash ./gradlew :benchmarks:e2e-benchmarks:shadowJar ``` -The jar lands at -`benchmarks/e2e-benchmarks/build/libs/smithy-java-e2e-benchmark-runner.jar`. +The jar lands at `benchmarks/e2e-benchmarks/build/libs/smithy-java-e2e-benchmark-runner.jar`. The build pulls AWS service models from Maven (`software.amazon.api.models:dynamodb` and `software.amazon.api.models:s3`) and codegens the typed DynamoDB and S3 @@ -37,16 +28,102 @@ don't collide. ```bash java -jar build/libs/smithy-java-e2e-benchmark-runner.jar \ - workloads/ddb-getitem-1KiB-latency-benchmark.json us-east-1 + --operation s3-put \ + --bucket my-bench--use1-az4--x-s3 \ + --region us-east-1 +``` + +Operations: + +| Operation | Workload | +|-----------|----------| +| `s3-put` | S3 PutObject, 256 KiB body, concurrent | +| `s3-get` | S3 GetObject, 256 KiB body, concurrent | +| `ddb-put` | DynamoDB PutItem, 1 KiB item, sequential | +| `ddb-get` | DynamoDB GetItem, 1 KiB item, sequential | + +Flags: + +| Flag | Notes | +|------|-------| +| `--operation ` | One of `s3-put`, `s3-get`, `ddb-put`, `ddb-get` | +| `--bucket ` | S3 Express directory bucket: `----x-s3` | +| `--table ` | Must have a `String` partition key named `pk` | +| `--region ` | Use the region the bucket / table lives in | +| `--client sync\|async` | Accepted for compatibility; smithy-java only supports sync | +| `--key-prefix ` | DynamoDB key prefix, default `item-` | +| `--s3-key-prefix ` | S3 key prefix, default `objects/256KiB/` | + +Common system properties: + +| Property | Default | +|----------|---------| +| `e2e.batch.actions` | `10000` for S3, `1000` for DynamoDB | +| `e2e.warmup.batches` | `2` | +| `e2e.measurement.batches` | `3` | +| `e2e.collectMetrics` | `true` | +| `e2e.object.size` | `262144` | +| `e2e.data.length` | `1024` | +| `e2e.ddb.createTable` | `true` | +| `e2e.ddb.deleteTable` | `true` | +| `e2e.ddb.readCapacityUnits` | `5000` | +| `e2e.ddb.writeCapacityUnits` | `5000` | + +## Provision the resources + +Run from an EC2 instance in the same AZ as the bucket. The instance role +needs `s3:CreateSession`, `s3express:*`, and `dynamodb:GetItem`/`PutItem` +on the resources below. + +S3 Express directory bucket (replace `my-bench` and `use1-az4` with your +own base name and availability zone): + +```bash +aws s3api create-bucket \ + --bucket my-bench--use1-az4--x-s3 \ + --region us-east-1 \ + --create-bucket-configuration '{ + "Location": {"Type": "AvailabilityZone", "Name": "use1-az4"}, + "Bucket": {"Type": "Directory", "DataRedundancy": "SingleAvailabilityZone"} + }' ``` -Region passed on the command line is ignored — the workload JSON is the -source of truth. +The S3 download workload reads keys named `objects/256KiB/`. Pre-seed +them by running the upload workload once first. -You can point the runner at any v1 workload JSON. +The DynamoDB workloads create a fresh provisioned table by default using +`--table` as the base name. The actual table name gets a run-specific suffix, +uses a `String` partition key named `pk`, defaults to `5000` RCU / `5000` WCU, +and is deleted after the run. The GetItem workload seeds its keys before warmup. + +To reuse an existing table instead: + +```bash +java -De2e.ddb.createTable=false -jar build/libs/smithy-java-e2e-benchmark-runner.jar \ + --operation ddb-get --table my-bench-table --region us-east-1 +``` + +## Cleanup + +```bash +aws s3 rm s3://my-bench--use1-az4--x-s3 --recursive --region us-east-1 +aws s3api delete-bucket --bucket my-bench--use1-az4--x-s3 --region us-east-1 +aws dynamodb delete-table --table-name my-bench-table --region us-east-1 +``` + +## Concurrency + +Throughput benchmarks dispatch each batch action onto a virtual thread, +gated by a semaphore. The cap is `cores × multiplier`, where `multiplier` +defaults to `4` and can be overridden: + +```bash +java -De2e.concurrency.multiplier=16 -jar build/libs/smithy-java-e2e-benchmark-runner.jar \ + --operation s3-put --bucket my-bench--use1-az4--x-s3 --region us-east-1 +``` ## Credentials -Credentials come from the AWS SDK v2 default credential provider chain -(env vars, profile file, container roles, IMDS). Override via the standard -SDK v2 environment variables. +Credentials are resolved from EC2 IMDSv2 directly. The benchmark is meant +to run on EC2 against directory buckets in the same AZ. For local testing +or non-EC2 hosts, supply credentials by extending the `Clients` factory. diff --git a/benchmarks/e2e-benchmarks/build.gradle.kts b/benchmarks/e2e-benchmarks/build.gradle.kts index 20b3feba07..080c24f014 100644 --- a/benchmarks/e2e-benchmarks/build.gradle.kts +++ b/benchmarks/e2e-benchmarks/build.gradle.kts @@ -1,3 +1,4 @@ +// Note: Not published plugins { id("smithy-java.java-conventions") id("com.gradleup.shadow") @@ -7,9 +8,6 @@ plugins { description = "End-to-end SDK benchmarks against live AWS services (DynamoDB GetItem/PutItem latency, S3 GetObject/PutObject throughput)." -// Not published. Mirrors the Java SDK v2 reference runner and reads the same -// workload JSON files so results are directly comparable. - application { mainClass.set("software.amazon.smithy.java.benchmarks.e2e.WorkloadRunner") } @@ -19,6 +17,11 @@ dependencies { smithyBuild(project(":codegen:codegen-plugin")) smithyBuild(project(":client:client-core")) smithyBuild(project(":client:client-waiters")) + // Needed at codegen time so RulesEngineBuilder loads AwsRulesExtension via ServiceLoader. + smithyBuild(project(":aws:client:aws-client-rulesengine")) + // Codegen needs the plugin class on its classpath so `Class.forName(...)` resolves it + // when wiring it into the generated client. + smithyBuild(project(":aws:aws-sigv4-s3express")) // AWS service models pulled from Maven (https://github.com/aws/api-models-aws). // The smithy-base plugin only loads models from sources + runtimeClasspath @@ -48,6 +51,7 @@ dependencies { // AWS-specific runtime: SigV4, AWS protocols, AWS endpoints. implementation(project(":aws:aws-sigv4")) + implementation(project(":aws:aws-sigv4-s3express")) implementation(project(":aws:aws-auth-api")) implementation(project(":aws:client:aws-client-core")) implementation(project(":aws:client:aws-client-http")) @@ -65,18 +69,18 @@ dependencies { implementation(libs.smithy.aws.traits) implementation(libs.smithy.model) - // smithy-java native credential chain — covers env vars, system props, - // shared config, web identity token, and ECS container slots out of the - // box; pulling in aws-credentials-imds adds the EC2 instance-metadata - // provider on top of it. Both modules register their providers via - // ServiceLoader, so just having them on the classpath is enough. + // smithy-java credential chain implementation(project(":aws:aws-credential-chain")) implementation(project(":aws:aws-credentials-imds")) + + // Alternate transports — selected at runtime via -De2e.transport=smithy|smithy-boringssl + implementation(project(":client:client-http-smithy")) + implementation(project(":client:client-http-boringssl")) } // Two projections so that DynamoDB and S3 generate into different namespaces -// and don't collide. Each projection filters down to just the ONE service -// it wants — the model JAR for s3 only has the s3 model, but the projection +// and don't collide. Each projection filters down to just the one service +// it wants; the model JAR for s3 only has the s3 model, but the projection // makes the intent explicit and gives us a stable name. val codegenProjections = listOf("dynamodb-client", "s3-client") @@ -104,7 +108,8 @@ tasks.named("processResources") { dependsOn("smithyBuild") } -// The shaded jar is the self-contained artifact users invoke to run a workload. +// The shaded jar is what users invoke from run-benchmark.py, mirroring +// `java -jar runners/java-workload-runner/target/workload-runner-1.0.0.jar`. tasks.named("shadowJar") { archiveBaseName.set("smithy-java-e2e-benchmark-runner") archiveClassifier.set("") @@ -123,7 +128,7 @@ tasks.named("assemble") { dependsOn("shadowJar") } -// Don't run benchmarks under `./gradlew check` — they hit live AWS. +// Don't run benchmarks under `./gradlew check`, they hit live AWS. tasks.named("check") { enabled = true } diff --git a/benchmarks/e2e-benchmarks/smithy-build.json b/benchmarks/e2e-benchmarks/smithy-build.json index 127e5a57be..81b4e40f4d 100644 --- a/benchmarks/e2e-benchmarks/smithy-build.json +++ b/benchmarks/e2e-benchmarks/smithy-build.json @@ -22,7 +22,12 @@ "transport": { "http-java": {} }, - "modes": ["client"] + "modes": ["client"], + "runtimeTraits": [ + "smithy.rules#contextParam", + "smithy.rules#staticContextParams", + "smithy.rules#operationContextParams" + ] } } }, @@ -47,7 +52,12 @@ "transport": { "http-java": {} }, - "modes": ["client"] + "modes": ["client"], + "runtimeTraits": [ + "smithy.rules#contextParam", + "smithy.rules#staticContextParams", + "smithy.rules#operationContextParams" + ] } } } diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ActionExecutor.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ActionExecutor.java index 12293d7080..ff7faae220 100644 --- a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ActionExecutor.java +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ActionExecutor.java @@ -6,7 +6,6 @@ package software.amazon.smithy.java.benchmarks.e2e; import java.io.IOException; -import java.io.OutputStream; import java.io.UncheckedIOException; import java.util.Map; import software.amazon.smithy.java.benchmarks.e2e.dynamodb.client.DynamoDBClient; @@ -19,10 +18,7 @@ import software.amazon.smithy.java.io.datastream.DataStream; /** - * Wraps the smithy-java DynamoDB and S3 clients with the four operations the - * benchmark exercises. Smithy-java currently only generates synchronous - * clients, so the throughput tests achieve concurrency by submitting work to - * a thread pool from {@link WorkloadRunner}. + * Wraps the smithy-java DynamoDB and S3 clients with the four operations the benchmark exercises. */ final class ActionExecutor { @@ -51,9 +47,8 @@ void getItem(String tableName, Map key) { } void putObject(String bucket, String key, int objectSize) { - // The reference runner reuses a single in-memory body across all - // uploads. DataStream.ofBytes wraps the array without copying, so - // each call is a thin handle over the same buffer. + // The reference runner reuses a single in-memory body across all uploads. + // DataStream.ofBytes wraps the array without copying, so each call is a thin handle over the same buffer. var body = DataStream.ofBytes(payload, 0, objectSize, "application/octet-stream"); s3.putObject(PutObjectInput.builder() .bucket(bucket) @@ -68,19 +63,14 @@ void getObject(String bucket, String key) { .bucket(bucket) .key(key) .build()); - // Drain the body so the download time is what we measure, not just - // the response headers. writeTo(nullOutputStream) walks the stream - // without forcing a single-contiguous-ByteBuffer materialization, so - // we exercise the SDK's most efficient consume path (multi-chunk - // delivery from the wire is fed straight through with no stitch). + // discard() drains and releases the underlying source. var body = output.getBody(); if (body != null) { try { - body.writeTo(OutputStream.nullOutputStream()); + body.discard(); } catch (IOException e) { - throw new UncheckedIOException("Failed to drain S3 GetObject body", e); + throw new UncheckedIOException("Failed to discard S3 GetObject body", e); } } } - } diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/BenchmarkSupport.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/BenchmarkSupport.java new file mode 100644 index 0000000000..fcfb347ee5 --- /dev/null +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/BenchmarkSupport.java @@ -0,0 +1,215 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.benchmarks.e2e; + +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +abstract class BenchmarkSupport { + + protected final BenchmarkConfig config; + private final int payloadSize; + private final long[] measuredDurationsNs; + private final AtomicInteger measuredCount = new AtomicInteger(); + private final ResourceMonitor monitor = new ResourceMonitor(); + + BenchmarkSupport(BenchmarkConfig config, int payloadSize) { + this.config = config; + this.payloadSize = payloadSize; + this.measuredDurationsNs = new long[config.measurementBatches() * config.batchActions()]; + printInit(); + } + + abstract void run(); + + protected final void runMeasured(Action action) { + try (ExecutorService pool = + config.operation().sequential ? null : Executors.newVirtualThreadPerTaskExecutor()) { + System.out.println("\n=== WARMUP PHASE ==="); + for (int i = 0; i < config.warmupBatches(); i++) { + System.out.println("Warmup batch " + (i + 1) + "/" + config.warmupBatches()); + executeBatch(pool, action, false); + } + measuredCount.set(0); + + System.out.println("\n=== MEASUREMENT PHASE ==="); + if (config.collectMetrics()) { + monitor.start(config.metricsIntervalMs()); + } + + long startNs = System.nanoTime(); + int lastSampleCount = 0; + for (int i = 0; i < config.measurementBatches(); i++) { + System.out.println("\nMeasurement batch " + (i + 1) + "/" + config.measurementBatches()); + int operationsBefore = measuredCount.get(); + long batchStart = System.nanoTime(); + executeBatch(pool, action, true); + long batchDuration = System.nanoTime() - batchStart; + printBatchResults(operationsBefore, batchDuration); + + if (config.collectMetrics()) { + int now = monitor.sampleCount(); + monitor.statsSnapshot(lastSampleCount).printCompact(" Resource Usage: "); + lastSampleCount = now; + } + } + long totalDuration = System.nanoTime() - startNs; + + if (config.collectMetrics()) { + monitor.stop().print(); + } + + System.out.println("\n=== OVERALL RESULTS ==="); + printOverall(totalDuration); + } + } + + private void executeBatch(ExecutorService pool, Action action, boolean measure) { + if (config.operation().sequential) { + for (int i = 0; i < config.batchActions(); i++) { + int preparedIndex = action.prepare(i); + long start = System.nanoTime(); + action.run(preparedIndex); + if (measure) { + recordDuration(System.nanoTime() - start); + } + } + return; + } + + int concurrency = Runtime.getRuntime().availableProcessors() + * Integer.getInteger("e2e.concurrency.multiplier", 4); + var permits = new Semaphore(concurrency); + var done = new CountDownLatch(config.batchActions()); + var error = new AtomicReference(); + for (int i = 0; i < config.batchActions(); i++) { + permits.acquireUninterruptibly(); + final int index = action.prepare(i); + pool.execute(() -> { + try { + long start = System.nanoTime(); + action.run(index); + if (measure) { + recordDuration(System.nanoTime() - start); + } + } catch (Throwable t) { + error.compareAndSet(null, t); + } finally { + permits.release(); + done.countDown(); + } + }); + } + try { + done.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for benchmark batch", e); + } + var failure = error.get(); + if (failure != null) { + throw new RuntimeException("Benchmark task failed", failure); + } + } + + private void recordDuration(long durationNs) { + measuredDurationsNs[measuredCount.getAndIncrement()] = durationNs; + } + + private void printInit() { + System.out.println("Initialized smithy-java e2e benchmark:"); + System.out.println(" Operation: " + config.operation().id); + System.out.println(" Region: " + config.region()); + if (config.operation().isS3()) { + System.out.println(" Bucket: " + config.bucketName()); + System.out.println(" Object: " + config.objectSize() + " bytes"); + } else { + System.out.println(" Table: " + config.tableName()); + } + System.out.println(" Sequential: " + config.operation().sequential); + System.out.println(" Actions per batch: " + config.batchActions()); + } + + private void printBatchResults(int startIndex, long batchDurationNs) { + int endIndex = measuredCount.get(); + if (endIndex <= startIndex) { + System.out.println(" No operations in this batch"); + return; + } + var batch = Arrays.copyOfRange(measuredDurationsNs, startIndex, endIndex); + Arrays.sort(batch); + int count = batch.length; + double batchSec = batchDurationNs / 1e9; + long totalBytes = (long) count * payloadSize; + double gbps = (totalBytes * 8.0 / batchSec) / 1e9; + long max = batch[count - 1]; + long p50 = batch[count / 2]; + long p90 = batch[(int) (count * 0.9)]; + long p99 = batch[(int) (count * 0.99)]; + double avgNs = average(batch, count); + System.out.printf(" Operations: %d, Duration: %.2fs, Throughput: %.2f Gbps%n", + count, + batchSec, + gbps); + System.out.printf(" Latency (ms) - Avg: %.2f, P50: %.2f, P90: %.2f, P99: %.2f, Max: %.2f%n", + avgNs / 1e6, + p50 / 1e6, + p90 / 1e6, + p99 / 1e6, + max / 1e6); + } + + private void printOverall(long totalDurationNs) { + int count = measuredCount.get(); + if (count == 0) { + System.out.println("No measurements collected"); + return; + } + Arrays.sort(measuredDurationsNs, 0, count); + double totalSec = totalDurationNs / 1e9; + long totalBytes = (long) count * payloadSize; + double gbps = (totalBytes * 8.0 / totalSec) / 1e9; + long min = measuredDurationsNs[0]; + long max = measuredDurationsNs[count - 1]; + long p50 = measuredDurationsNs[count / 2]; + long p90 = measuredDurationsNs[(int) (count * 0.9)]; + long p99 = measuredDurationsNs[(int) (count * 0.99)]; + double avgNs = average(measuredDurationsNs, count); + System.out.println("Total operations: " + count); + System.out.printf("Total data transferred: %.2f MiB%n", totalBytes / 1024.0 / 1024.0); + System.out.printf("Total duration: %.2f seconds%n", totalSec); + System.out.printf("Throughput: %.2f Gbps%n", gbps); + System.out.println("\nLatency (milliseconds):"); + System.out.printf(" Average: %.2f%n", avgNs / 1e6); + System.out.printf(" Minimum: %.2f%n", min / 1e6); + System.out.printf(" P50: %.2f%n", p50 / 1e6); + System.out.printf(" P90: %.2f%n", p90 / 1e6); + System.out.printf(" P99: %.2f%n", p99 / 1e6); + System.out.printf(" Maximum: %.2f%n", max / 1e6); + } + + private static double average(long[] values, int count) { + long sum = 0; + for (int i = 0; i < count; i++) { + sum += values[i]; + } + return count == 0 ? 0 : (double) sum / count; + } + + @FunctionalInterface + protected interface Action { + default int prepare(int index) { + return index; + } + + void run(int index); + } +} diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/Clients.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/Clients.java index 4e6959e26d..76ced957d5 100644 --- a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/Clients.java +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/Clients.java @@ -7,27 +7,27 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.IntConsumer; import software.amazon.smithy.java.auth.api.identity.IdentityResolver; import software.amazon.smithy.java.aws.auth.api.identity.AwsCredentialsIdentity; +import software.amazon.smithy.java.aws.client.auth.scheme.s3express.CreateSessionCallback; +import software.amazon.smithy.java.aws.client.auth.scheme.s3express.S3ExpressContext; import software.amazon.smithy.java.aws.client.core.settings.RegionSetting; import software.amazon.smithy.java.aws.credentials.chain.ChainSetup; import software.amazon.smithy.java.aws.credentials.imds.ImdsCredentialProvider; import software.amazon.smithy.java.benchmarks.e2e.dynamodb.client.DynamoDBClient; import software.amazon.smithy.java.benchmarks.e2e.s3.client.S3Client; +import software.amazon.smithy.java.benchmarks.e2e.s3.model.CreateSessionInput; +import software.amazon.smithy.java.client.core.ClientTransport; +import software.amazon.smithy.java.client.http.boringssl.BoringSslTlsProvider; +import software.amazon.smithy.java.client.http.smithy.SmithyHttpClientTransport; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; /** - * Constructs the smithy-java-generated DynamoDB and S3 clients used by the - * benchmark. Region comes from the workload's actionConfig; credentials come - * directly from the EC2 IMDSv2 endpoint. - * - *

Why we bypass the standard {@code CredentialChain}: the - * {@code SystemPropertiesCredentialProvider} and - * {@code EnvironmentCredentialProvider} both call - * {@code ChainSetup.addTerminalResolver} unconditionally during assembly, - * which stops the chain after the first provider regardless of whether - * credentials are actually present. That makes IMDS unreachable on EC2 - * instances. The benchmark always runs on EC2, so wiring IMDS directly is - * both correct and avoids the bug. + * Constructs the smithy-java-generated DynamoDB and S3 clients used by the benchmark. + * Region comes from the benchmark runner; credentials come directly from the EC2 IMDSv2 endpoint. */ final class Clients { @@ -35,18 +35,144 @@ final class Clients { private Clients() {} + /** + * Apply a {@code -D=} socket-buffer knob: use the property value when set + * (where {@code auto}/{@code -1} means "kernel autotune"), otherwise apply {@code defaultBytes}. + * Pass {@code -1} as the default to leave the socket at kernel autotune when the property is unset. + */ + private static void applyBufferProp(String prop, int defaultBytes, IntConsumer setter) { + Integer value = parseBufferProp(prop); + int bytes = value != null ? value : defaultBytes; + // -1 == kernel autotune: leave the socket option unset. + if (bytes != -1) { + setter.accept(bytes); + } + } + + /** + * Apply a TLS buffer-size knob: use {@code -D=} when set, else {@code defaultBytes}. + * Unlike the socket SO_*BUF knobs there is no "auto"/-1 form — these are concrete buffer + * capacities, not a kernel-autotune toggle — so a value of -1 is rejected. + */ + private static void applyTlsBufferProp(String prop, int defaultBytes, IntConsumer setter) { + Integer value = parseBufferProp(prop); + int bytes = value != null ? value : defaultBytes; + if (bytes <= 0) { + throw new IllegalArgumentException(prop + " must be a positive byte count: " + bytes); + } + setter.accept(bytes); + } + + /** + * Parse a {@code -D=} property: {@code -1} for "auto", null if unset. + */ + private static Integer parseBufferProp(String prop) { + var value = System.getProperty(prop); + if (value == null) { + return null; + } + var trimmed = value.trim().toLowerCase(); + return "auto".equals(trimmed) ? -1 : Integer.parseInt(trimmed); + } + + private static int maxConnections() { + return Integer.getInteger("e2e.maxconns", 1024); + } + + /** + * Returns the alternate transport selected via {@code -De2e.transport=...}, or null for the + * default JDK HttpClient. Recognized values: {@code smithy}, {@code smithy-boringssl}. + */ + private static ClientTransport selectTransport() { + var name = System.getProperty("e2e.transport", "").trim().toLowerCase(); + return switch (name) { + case "", "jdk" -> null; + case "smithy" -> new SmithyHttpClientTransport(smithyPool(false)); + // Same smithy native transport, but TLS is driven by the BoringSSL (netty-tcnative) + // SSLEngine instead of the JDK engine — keeps the cheaper AES-GCM without the Netty + // pipeline. Falls back to the JDK provider if tcnative is unavailable on the host. + case "smithy-boringssl" -> new SmithyHttpClientTransport(smithyPool(true)); + default -> throw new IllegalArgumentException( + "Unknown e2e.transport: '" + name + + "' (expected one of: jdk, smithy, smithy-boringssl)"); + }; + } + + /** + * Build the smithy native transport's HTTP client. Shared by the {@code smithy} and + * {@code smithy-boringssl} variants; the latter injects the BoringSSL SSLEngine factory. + * + *

Smithy HTTP client defaults to ENFORCE_HTTP_2 which fails on S3 (H1-only); AUTOMATIC also + * fails (the pool routes HTTPS to the H2 manager, which refuses an ALPN result of "http/1.1"). + * Force ENFORCE_HTTP_1_1 so the pool routes to the H1 manager from the start. The pool's default + * maxConnectionsPerRoute=20 throttles a single-bucket benchmark hard, so use the shared + * -De2e.maxconns cap (default unbounded) for equal footing with netty. + */ + private static HttpClient smithyPool(boolean boringSsl) { + int maxConns = maxConnections(); + var builder = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(maxConns) + .maxConnectionsPerRoute(maxConns); + applyBufferProp("e2e.smithy.recvbuf", 1024 * 1024, builder::socketReceiveBufferSize); + applyBufferProp("e2e.smithy.sendbuf", 1024 * 1024, builder::socketSendBufferSize); + applyTlsBufferProp("e2e.smithy.tls.readbuf", 256 * 1024, builder::tlsReadBufferSize); + applyTlsBufferProp("e2e.smithy.tls.writebuf", 256 * 1024, builder::tlsWriteBufferSize); + // The epoll transport is selected automatically when the native library is available. + if (boringSsl) { + if (BoringSslTlsProvider.available()) { + builder.tlsProvider(BoringSslTlsProvider.create(false)); + } else { + System.err.println("smithy-boringssl requested but netty-tcnative unavailable; " + + "using JDK SSLEngine"); + } + } + return builder.build(); + } + static DynamoDBClient dynamodb(String region) { - return DynamoDBClient.builder() + var b = DynamoDBClient.builder() .putConfig(RegionSetting.REGION, region) - .addIdentityResolver(IMDS) - .build(); + .addIdentityResolver(IMDS); + var transport = selectTransport(); + if (transport != null) { + b.transport(transport); + } + return b.build(); } static S3Client s3(String region) { - return S3Client.builder() + // S3ExpressPlugin is an AutoClientPlugin discovered via ServiceLoader. It reads + // CREATE_SESSION_CALLBACK from the builder's context and (when present) registers + // S3ExpressAuthScheme + the bucket interceptor + disable-session-auth resolver. We + // just have to provide the callback that can call createSession on the same client + // we're configuring — chicken-and-egg resolved by an AtomicReference that gets + // populated after build(). TODO: fix + var clientRef = new AtomicReference(); + CreateSessionCallback createSession = (bucket, baseCreds) -> { + S3Client client = clientRef.get(); + if (client == null) { + throw new IllegalStateException("S3 client not yet initialized; cannot CreateSession"); + } + var resp = client.createSession(CreateSessionInput.builder().bucket(bucket).build()); + var c = resp.getCredentials(); + return AwsCredentialsIdentity.create( + c.getAccessKeyId(), + c.getSecretAccessKey(), + c.getSessionToken(), + c.getExpiration()); + }; + var b = S3Client.builder() .putConfig(RegionSetting.REGION, region) - .addIdentityResolver(IMDS) - .build(); + .putConfig(S3ExpressContext.CREATE_SESSION_CALLBACK, createSession) + .addIdentityResolver(IMDS); + var transport = selectTransport(); + if (transport != null) { + b.transport(transport); + } + S3Client client = b.build(); + clientRef.set(client); + return client; } @SuppressWarnings("unchecked") @@ -64,6 +190,6 @@ private static IdentityResolver buildImds() { if (resolvers.isEmpty()) { throw new IllegalStateException("IMDS provider did not register a resolver"); } - return (IdentityResolver) resolvers.get(0).resolver(); + return (IdentityResolver) resolvers.getFirst().resolver(); } } diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/DdbBenchmarks.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/DdbBenchmarks.java new file mode 100644 index 0000000000..6a51c43fbe --- /dev/null +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/DdbBenchmarks.java @@ -0,0 +1,169 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.benchmarks.e2e; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.function.IntConsumer; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.client.DynamoDBClient; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.AttributeDefinition; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.AttributeValue; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.BillingMode; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.CreateTableInput; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.DeleteTableInput; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.DescribeTableInput; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.KeySchemaElement; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.KeyType; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.ProvisionedThroughput; +import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.ScalarAttributeType; + +final class DdbBenchmarks extends BenchmarkSupport { + + private static final Duration DEFAULT_DDB_WAITER_TIMEOUT = Duration.ofMinutes(5); + private static final int KEY_COUNT = 100; + + private final String dataPayload; + + DdbBenchmarks(BenchmarkConfig config) { + super(config, switch (config.operation()) { + case DDB_PUT -> config.dataLength(); + case DDB_GET -> 1024; + default -> throw new IllegalStateException("Unsupported DynamoDB operation: " + config.operation()); + }); + this.dataPayload = "x".repeat(config.dataLength()); + } + + @Override + void run() { + switch (config.operation()) { + case DDB_PUT -> runPutItem(); + case DDB_GET -> runGetItem(); + default -> throw new IllegalStateException("Unsupported DynamoDB operation: " + config.operation()); + } + } + + private void runPutItem() { + var client = Clients.dynamodb(config.region()); + try (var table = DdbTable.setup(client, config)) { + var executor = new ActionExecutor(client, null, new byte[0]); + runMeasured(cyclingAction(keyIndex -> executor.putItem(table.name(), buildItem(keyIndex)))); + } + } + + private void runGetItem() { + var client = Clients.dynamodb(config.region()); + try (var table = DdbTable.setup(client, config)) { + var executor = new ActionExecutor(client, null, new byte[0]); + if (table.created()) { + System.out.println("Seeding DynamoDB GetItem keys: " + KEY_COUNT); + for (int i = 0; i < KEY_COUNT; i++) { + executor.putItem(table.name(), buildItem(i)); + } + } + runMeasured(cyclingAction(keyIndex -> executor.getItem(table.name(), buildKey(keyIndex)))); + } + } + + private Action cyclingAction(IntConsumer operation) { + return new Action() { + private int currentKeyIndex; + + @Override + public int prepare(int index) { + currentKeyIndex = (currentKeyIndex + 1) % KEY_COUNT; + return currentKeyIndex; + } + + @Override + public void run(int keyIndex) { + operation.accept(keyIndex); + } + }; + } + + private Map buildKey(int index) { + var pk = AttributeValue.builder().s(ddbKey(index)).build(); + return Map.of("pk", pk); + } + + private Map buildItem(int index) { + var pk = AttributeValue.builder().s(ddbKey(index)).build(); + var data = AttributeValue.builder().s(dataPayload).build(); + return Map.of("pk", pk, "data", data); + } + + private String ddbKey(int index) { + return config.keyPrefix() + index; + } + + private record DdbTable(DynamoDBClient client, String name, boolean created, boolean deleteOnClose) + implements AutoCloseable { + + private static DdbTable setup(DynamoDBClient client, BenchmarkConfig config) { + if (!config.ddbCreateTable()) { + System.out.println("Using existing DynamoDB table: " + config.tableName()); + return new DdbTable(client, config.tableName(), false, false); + } + + var tableName = uniqueTableName(config.tableName(), config.operation().id); + System.out.println("Creating DynamoDB table: " + tableName + + " (PROVISIONED " + + config.ddbReadCapacityUnits() + " RCU / " + + config.ddbWriteCapacityUnits() + " WCU)"); + client.createTable(CreateTableInput.builder() + .tableName(tableName) + .attributeDefinitions(List.of(AttributeDefinition.builder() + .attributeName("pk") + .attributeType(ScalarAttributeType.S) + .build())) + .keySchema(List.of(KeySchemaElement.builder() + .attributeName("pk") + .keyType(KeyType.HASH) + .build())) + .billingMode(BillingMode.PROVISIONED) + .provisionedThroughput(ProvisionedThroughput.builder() + .readCapacityUnits(config.ddbReadCapacityUnits()) + .writeCapacityUnits(config.ddbWriteCapacityUnits()) + .build()) + .build()); + var describe = describeInput(tableName); + client.waiter().tableExists().wait(describe, DEFAULT_DDB_WAITER_TIMEOUT); + System.out.println("DynamoDB table active: " + tableName); + return new DdbTable(client, tableName, true, config.ddbDeleteTable()); + } + + @Override + public void close() { + if (!deleteOnClose) { + return; + } + System.out.println("Deleting DynamoDB table: " + name); + try { + client.deleteTable(DeleteTableInput.builder() + .tableName(name) + .build()); + client.waiter().tableNotExists().wait(describeInput(name), DEFAULT_DDB_WAITER_TIMEOUT); + } catch (RuntimeException e) { + System.err.println("WARNING: failed to delete DynamoDB table " + name + ": " + e); + e.printStackTrace(System.err); + } + } + + private static DescribeTableInput describeInput(String tableName) { + return DescribeTableInput.builder() + .tableName(tableName) + .build(); + } + + private static String uniqueTableName(String baseName, String operation) { + var suffix = "-" + operation + "-" + Long.toUnsignedString(System.currentTimeMillis(), 36); + var maxBaseLength = 255 - suffix.length(); + var prefix = baseName.length() > maxBaseLength ? baseName.substring(0, maxBaseLength) : baseName; + return prefix + suffix; + } + } +} diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ResourceMonitor.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ResourceMonitor.java index 984f9bcc87..1c37fbfbf9 100644 --- a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ResourceMonitor.java +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/ResourceMonitor.java @@ -6,6 +6,7 @@ package software.amazon.smithy.java.benchmarks.e2e; import com.sun.management.OperatingSystemMXBean; +import java.lang.management.BufferPoolMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.util.ArrayList; @@ -22,53 +23,99 @@ final class ResourceMonitor { private final OperatingSystemMXBean osMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); private final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + private final BufferPoolMXBean directBufferPool = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class) + .stream() + .filter(b -> "direct".equals(b.getName())) + .findFirst() + .orElse(null); private final List samples = new ArrayList<>(); private ScheduledExecutorService scheduler; static final class Sample { final double cpuPercent; - final long memoryBytes; + final long heapBytes; + final long nonHeapBytes; + final long directBytes; - Sample(double cpu, long mem) { + Sample(double cpu, long heap, long nonHeap, long direct) { this.cpuPercent = cpu; - this.memoryBytes = mem; + this.heapBytes = heap; + this.nonHeapBytes = nonHeap; + this.directBytes = direct; } } static final class Stats { final double cpuMean; final double cpuMax; - final long memMean; - final long memMax; + final long heapMean; + final long heapMax; + final long nonHeapMean; + final long nonHeapMax; + final long directMean; + final long directMax; final int sampleCount; - Stats(double cpuMean, double cpuMax, long memMean, long memMax, int sampleCount) { + Stats( + double cpuMean, + double cpuMax, + long heapMean, + long heapMax, + long nonHeapMean, + long nonHeapMax, + long directMean, + long directMax, + int sampleCount + ) { this.cpuMean = cpuMean; this.cpuMax = cpuMax; - this.memMean = memMean; - this.memMax = memMax; + this.heapMean = heapMean; + this.heapMax = heapMax; + this.nonHeapMean = nonHeapMean; + this.nonHeapMax = nonHeapMax; + this.directMean = directMean; + this.directMax = directMax; this.sampleCount = sampleCount; } + long memMean() { + return heapMean + nonHeapMean + directMean; + } + + long memMax() { + return heapMax + nonHeapMax + directMax; + } + void print() { System.out.println("\n=== Resource Usage Statistics ==="); System.out.printf("Samples collected: %d%n", sampleCount); System.out.println("\nCPU Usage:"); System.out.printf(" Mean: %.1f%%%n", cpuMean); System.out.printf(" Max: %.1f%%%n", cpuMax); - System.out.println("\nMemory Usage:"); - System.out.printf(" Mean: %.1f MB%n", memMean / 1024.0 / 1024.0); - System.out.printf(" Max: %.1f MB%n", memMax / 1024.0 / 1024.0); + System.out.println("\nMemory Usage (mean / max):"); + System.out.printf(" Heap: %6.1f / %6.1f MB%n", heapMean / 1024.0 / 1024.0, heapMax / 1024.0 / 1024.0); + System.out.printf(" Non-heap: %6.1f / %6.1f MB%n", + nonHeapMean / 1024.0 / 1024.0, + nonHeapMax / 1024.0 / 1024.0); + System.out.printf(" Direct: %6.1f / %6.1f MB%n", + directMean / 1024.0 / 1024.0, + directMax / 1024.0 / 1024.0); + System.out.printf(" Total: %6.1f / %6.1f MB%n", + memMean() / 1024.0 / 1024.0, + memMax() / 1024.0 / 1024.0); System.out.println("================================="); } void printCompact(String prefix) { - System.out.printf("%sCPU: %.1f%% (max: %.1f%%), Memory: %.1f MB (max: %.1f MB)%n", + System.out.printf( + "%sCPU: %.1f%% (max: %.1f%%), Heap: %.1f MB (max: %.1f MB), Direct: %.1f MB (max: %.1f MB)%n", prefix, cpuMean, cpuMax, - memMean / 1024.0 / 1024.0, - memMax / 1024.0 / 1024.0); + heapMean / 1024.0 / 1024.0, + heapMax / 1024.0 / 1024.0, + directMean / 1024.0 / 1024.0, + directMax / 1024.0 / 1024.0); } } @@ -109,24 +156,40 @@ synchronized int sampleCount() { private synchronized Stats computeStats(int startIndex) { if (startIndex >= samples.size()) { - return new Stats(0, 0, 0, 0, 0); + return new Stats(0, 0, 0, 0, 0, 0, 0, 0, 0); } var window = new ArrayList<>(samples.subList(startIndex, samples.size())); if (window.isEmpty()) { - return new Stats(0, 0, 0, 0, 0); + return new Stats(0, 0, 0, 0, 0, 0, 0, 0, 0); } double cpuSum = 0; double cpuMax = 0; - long memSum = 0; - long memMax = 0; + long heapSum = 0; + long heapMax = 0; + long nonHeapSum = 0; + long nonHeapMax = 0; + long directSum = 0; + long directMax = 0; for (var s : window) { cpuSum += s.cpuPercent; cpuMax = Math.max(cpuMax, s.cpuPercent); - memSum += s.memoryBytes; - memMax = Math.max(memMax, s.memoryBytes); + heapSum += s.heapBytes; + heapMax = Math.max(heapMax, s.heapBytes); + nonHeapSum += s.nonHeapBytes; + nonHeapMax = Math.max(nonHeapMax, s.nonHeapBytes); + directSum += s.directBytes; + directMax = Math.max(directMax, s.directBytes); } int count = window.size(); - return new Stats(cpuSum / count, cpuMax, memSum / count, memMax, count); + return new Stats(cpuSum / count, + cpuMax, + heapSum / count, + heapMax, + nonHeapSum / count, + nonHeapMax, + directSum / count, + directMax, + count); } private synchronized void sample() { @@ -134,8 +197,9 @@ private synchronized void sample() { if (cpu < 0) { cpu = 0; } - long mem = memoryMXBean.getHeapMemoryUsage().getUsed() - + memoryMXBean.getNonHeapMemoryUsage().getUsed(); - samples.add(new Sample(cpu * 100.0, mem)); + long heap = memoryMXBean.getHeapMemoryUsage().getUsed(); + long nonHeap = memoryMXBean.getNonHeapMemoryUsage().getUsed(); + long direct = directBufferPool != null ? directBufferPool.getMemoryUsed() : 0; + samples.add(new Sample(cpu * 100.0, heap, nonHeap, direct)); } } diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/S3Benchmarks.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/S3Benchmarks.java new file mode 100644 index 0000000000..4f57d8d7bc --- /dev/null +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/S3Benchmarks.java @@ -0,0 +1,42 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.benchmarks.e2e; + +import java.util.Random; + +final class S3Benchmarks extends BenchmarkSupport { + + private final byte[] payload; + + S3Benchmarks(BenchmarkConfig config) { + super(config, config.objectSize()); + this.payload = new byte[Math.max(config.objectSize(), 1)]; + new Random(0xC0FFEEL).nextBytes(payload); + } + + @Override + void run() { + switch (config.operation()) { + case S3_PUT -> runPutObject(); + case S3_GET -> runGetObject(); + default -> throw new IllegalStateException("Unsupported S3 operation: " + config.operation()); + } + } + + private void runPutObject() { + var executor = new ActionExecutor(null, Clients.s3(config.region()), payload); + runMeasured(index -> executor.putObject(config.bucketName(), s3Key(index), config.objectSize())); + } + + private void runGetObject() { + var executor = new ActionExecutor(null, Clients.s3(config.region()), payload); + runMeasured(index -> executor.getObject(config.bucketName(), s3Key(index))); + } + + private String s3Key(int index) { + return config.s3KeyPrefix() + (index + 1); + } +} diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadConfig.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadConfig.java deleted file mode 100644 index fb7272b309..0000000000 --- a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadConfig.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.java.benchmarks.e2e; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import software.amazon.smithy.model.node.Node; -import software.amazon.smithy.model.node.ObjectNode; - -/** - * In-memory representation of a workload JSON file. - * - *

Only the v1 fields used by smithy-java's runner are exposed. Unknown - * fields are ignored so that newer workload files do not break older runners. - */ -final class WorkloadConfig { - final String name; - final String service; // "dynamodb" or "s3" - final String action; // "putitem" / "getitem" / "upload" / "download" - final ObjectNode actionConfig; - final int batchActions; - final boolean sequential; - final int warmupBatches; - final int measurementBatches; - final boolean collectMetrics; - final int metricsIntervalMs; - - private WorkloadConfig(ObjectNode root) { - this.name = root.expectStringMember("name").getValue(); - this.service = root.expectStringMember("service").getValue(); - this.action = root.expectStringMember("action").getValue(); - this.actionConfig = root.expectObjectMember("actionConfig"); - - var batch = root.expectObjectMember("batch"); - this.batchActions = batch.expectNumberMember("numberOfActions").getValue().intValue(); - this.sequential = batch.expectBooleanMember("sequentialExecution").getValue(); - - this.warmupBatches = root.expectObjectMember("warmup") - .expectNumberMember("batches") - .getValue() - .intValue(); - - var measurement = root.expectObjectMember("measurement"); - this.measurementBatches = measurement.expectNumberMember("batches").getValue().intValue(); - this.collectMetrics = measurement.getBooleanMember("collectMetrics") - .map(b -> b.getValue()) - .orElse(false); - this.metricsIntervalMs = measurement.getNumberMember("metricsInterval") - .map(n -> n.getValue().intValue()) - .orElse(100); - } - - static WorkloadConfig load(String path) throws IOException { - var bytes = Files.readAllBytes(Paths.get(path)); - var node = Node.parse(new String(bytes)).expectObjectNode(); - return new WorkloadConfig(node); - } - - String stringConfig(String name) { - return actionConfig.expectStringMember(name).getValue(); - } - - int intConfig(String name) { - return actionConfig.expectNumberMember(name).getValue().intValue(); - } -} diff --git a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadRunner.java b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadRunner.java index bf52e49429..c1c9b6de95 100644 --- a/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadRunner.java +++ b/benchmarks/e2e-benchmarks/src/main/java/software/amazon/smithy/java/benchmarks/e2e/WorkloadRunner.java @@ -5,360 +5,53 @@ package software.amazon.smithy.java.benchmarks.e2e; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.logging.LogManager; import java.util.logging.Logger; -import software.amazon.smithy.java.benchmarks.e2e.dynamodb.model.AttributeValue; /** - * smithy-java implementation of the e2e benchmark workload runner. Reads the - * workload JSON spec and produces results comparable to the reference Java SDK - * v2 runner. - * - *

Limitations: - * - *

    - *
  • smithy-java's generated clients are synchronous; there is no - * {@code xxxAsync} API. The {@code --client async} flag from the - * reference runner is not accepted. Throughput-style workloads still - * drive concurrency through a thread pool, which is the SDK's - * idiomatic concurrency pattern.
  • - *
+ * Front door for the fixed live AWS e2e benchmarks. */ public final class WorkloadRunner { - private final WorkloadConfig workload; - private final ActionExecutor executor; - private final byte[] payload; - private final int payloadSize; - private final List measuredDurationsNs = Collections.synchronizedList(new ArrayList<>()); - private final ResourceMonitor monitor = new ResourceMonitor(); + private WorkloadRunner() {} - private WorkloadRunner(WorkloadConfig workload) { - this.workload = workload; - this.payloadSize = maxPayloadSize(workload); - this.payload = new byte[payloadSize]; - new Random(0xC0FFEEL).nextBytes(payload); - - var region = workload.stringConfig("region"); - var ddb = "dynamodb".equals(workload.service) ? Clients.dynamodb(region) : null; - var s3 = "s3".equals(workload.service) ? Clients.s3(region) : null; - if (ddb == null && s3 == null) { - throw new IllegalArgumentException("Unknown service: " + workload.service); - } - // Build the unused client too — the executor stores nullable refs and - // the runner only invokes the path matching workload.service. - this.executor = new ActionExecutor( - ddb == null ? Clients.dynamodb(region) : ddb, - s3 == null ? Clients.s3(region) : s3, - payload); - - System.out.println("Initialized smithy-java WorkloadRunner:"); - System.out.println(" Workload: " + workload.name); - System.out.println(" Service: " + workload.service); - System.out.println(" Action: " + workload.action); - System.out.println(" Region: " + region); - System.out.println(" Sequential: " + workload.sequential); - System.out.println(" Actions per batch: " + workload.batchActions); - } - - private static int maxPayloadSize(WorkloadConfig w) { - if ("s3".equals(w.service)) { - return w.intConfig("objectSize"); - } - // DDB putitem has dataLength; getitem doesn't. Either way 1KiB is - // a safe default that won't be hit on getitem. - if (w.actionConfig.getMember("dataLength").isPresent()) { - return w.intConfig("dataLength"); - } - return 1024; - } - - private void run() { - System.out.println("\n=== WARMUP PHASE ==="); - System.out.println("Executing " + workload.warmupBatches + " warmup batches to initialize SDK clients..."); - for (int i = 0; i < workload.warmupBatches; i++) { - System.out.println("Warmup batch " + (i + 1) + "/" + workload.warmupBatches); - executeBatch(false); - } - measuredDurationsNs.clear(); - - System.out.println("\n=== MEASUREMENT PHASE ==="); - System.out.println("Executing " + workload.measurementBatches + " measurement batches..."); - - if (workload.collectMetrics) { - monitor.start(workload.metricsIntervalMs); - } - - long startNs = System.nanoTime(); - int lastSampleCount = 0; - for (int i = 0; i < workload.measurementBatches; i++) { - System.out.println("\nMeasurement batch " + (i + 1) + "/" + workload.measurementBatches); - int operationsBefore = measuredDurationsNs.size(); - long batchStart = System.nanoTime(); - executeBatch(true); - long batchDuration = System.nanoTime() - batchStart; - printBatchResults(operationsBefore, batchDuration); - - if (workload.collectMetrics) { - int now = monitor.sampleCount(); - monitor.statsSnapshot(lastSampleCount).printCompact(" Resource Usage: "); - lastSampleCount = now; - } - } - long totalDuration = System.nanoTime() - startNs; - - if (workload.collectMetrics) { - monitor.stop().print(); - } - - System.out.println("\n=== OVERALL RESULTS ==="); - printOverall(totalDuration); - } + public static void main(String[] args) { + configureRuntime(); + printActiveJsonProvider(); - private void executeBatch(boolean measure) { - if (workload.sequential) { - for (int i = 0; i < workload.batchActions; i++) { - long s = System.nanoTime(); - executeAction(i); - long d = System.nanoTime() - s; - if (measure) { - measuredDurationsNs.add(d); - } - } + var config = BenchmarkConfig.parse(args); + if (config.operation().isS3()) { + new S3Benchmarks(config).run(); } else { - // The reference runner uses 2x cores; smithy-java's blocking - // client is idiomatically driven from a thread pool, so match - // it for fair comparison. - int threads = Runtime.getRuntime().availableProcessors() * 2; - ExecutorService pool = Executors.newFixedThreadPool(threads, r -> { - var t = new Thread(r, "e2e-worker"); - t.setDaemon(true); - return t; - }); - List> futures = new ArrayList<>(workload.batchActions); - for (int i = 0; i < workload.batchActions; i++) { - final int index = i; - futures.add(pool.submit(() -> { - long s = System.nanoTime(); - executeAction(index); - return System.nanoTime() - s; - })); - } - for (var f : futures) { - try { - long d = f.get(); - if (measure) { - measuredDurationsNs.add(d); - } - } catch (Exception e) { - System.err.println("Task failed: " + e.getMessage()); - e.printStackTrace(); - } - } - pool.shutdown(); - try { - pool.awaitTermination(5, TimeUnit.MINUTES); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - - private void executeAction(int index) { - var action = workload.action; - try { - if ("s3".equals(workload.service)) { - var bucket = workload.stringConfig("bucketName"); - var key = generateKey(index); - if ("upload".equals(action)) { - executor.putObject(bucket, key, workload.intConfig("objectSize")); - } else if ("download".equals(action)) { - executor.getObject(bucket, key); - } else { - throw new IllegalArgumentException("Unknown S3 action: " + action); - } - } else if ("dynamodb".equals(workload.service)) { - var tableName = workload.stringConfig("tableName"); - if ("putitem".equals(action)) { - executor.putItem(tableName, buildItem(index)); - } else if ("getitem".equals(action)) { - Map key = new HashMap<>(); - key.put("pk", AttributeValue.builder().s(generateKey(index)).build()); - executor.getItem(tableName, key); - } else { - throw new IllegalArgumentException("Unknown DynamoDB action: " + action); - } - } - } catch (RuntimeException e) { - System.err.println("Action failed: service=" + workload.service + ", action=" + action); - System.err.println("Error: " + e.getClass().getName() + ": " + e.getMessage()); - if (e.getCause() != null) { - System.err - .println("Caused by: " + e.getCause().getClass().getName() + ": " + e.getCause().getMessage()); - } - throw e; - } - } - - private Map buildItem(int index) { - Map item = new HashMap<>(); - item.put("pk", AttributeValue.builder().s(generateKey(index)).build()); - int dataLength = workload.intConfig("dataLength"); - item.put("data", AttributeValue.builder().s(randomString(dataLength)).build()); - return item; - } - - private String generateKey(int index) { - return workload.stringConfig("keyPrefix") + (index + 1); - } - - private static String randomString(int length) { - // Reference runner uses [A-Za-z0-9]; matched here for byte-for-byte - // compatibility on the wire. - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - var random = new Random(); - var sb = new StringBuilder(length); - for (int i = 0; i < length; i++) { - sb.append(chars.charAt(random.nextInt(chars.length()))); - } - return sb.toString(); - } - - private void printBatchResults(int startIndex, long batchDurationNs) { - int endIndex = measuredDurationsNs.size(); - if (endIndex <= startIndex) { - System.out.println(" No operations in this batch"); - return; + new DdbBenchmarks(config).run(); } - var batch = new ArrayList<>(measuredDurationsNs.subList(startIndex, endIndex)); - Collections.sort(batch); - int count = batch.size(); - double batchSec = batchDurationNs / 1e9; - long totalBytes = (long) count * payloadSize; - double gbps = (totalBytes * 8.0 / batchSec) / 1e9; - long max = batch.get(count - 1); - long p50 = batch.get(count / 2); - long p90 = batch.get((int) (count * 0.9)); - long p99 = batch.get((int) (count * 0.99)); - double avgNs = batch.stream().mapToLong(Long::longValue).average().orElse(0); - System.out.printf(" Operations: %d, Duration: %.2fs, Throughput: %.2f Gbps%n", - count, - batchSec, - gbps); - System.out.printf(" Latency (ms) - Avg: %.2f, P50: %.2f, P90: %.2f, P99: %.2f, Max: %.2f%n", - avgNs / 1e6, - p50 / 1e6, - p90 / 1e6, - p99 / 1e6, - max / 1e6); } - private void printOverall(long totalDurationNs) { - if (measuredDurationsNs.isEmpty()) { - System.out.println("No measurements collected"); - return; - } - Collections.sort(measuredDurationsNs); - int count = measuredDurationsNs.size(); - double totalSec = totalDurationNs / 1e9; - long totalBytes = (long) count * payloadSize; - double gbps = (totalBytes * 8.0 / totalSec) / 1e9; - long min = measuredDurationsNs.get(0); - long max = measuredDurationsNs.get(count - 1); - long p50 = measuredDurationsNs.get(count / 2); - long p90 = measuredDurationsNs.get((int) (count * 0.9)); - long p99 = measuredDurationsNs.get((int) (count * 0.99)); - double avgNs = measuredDurationsNs.stream().mapToLong(Long::longValue).average().orElse(0); - System.out.println("Total operations: " + count); - System.out.printf("Total data transferred: %.2f MiB%n", totalBytes / 1024.0 / 1024.0); - System.out.printf("Total duration: %.2f seconds%n", totalSec); - System.out.printf("Throughput: %.2f Gbps%n", gbps); - System.out.println("\nLatency (milliseconds):"); - System.out.printf(" Average: %.2f%n", avgNs / 1e6); - System.out.printf(" Minimum: %.2f%n", min / 1e6); - System.out.printf(" P50: %.2f%n", p50 / 1e6); - System.out.printf(" P90: %.2f%n", p90 / 1e6); - System.out.printf(" P99: %.2f%n", p99 / 1e6); - System.out.printf(" Maximum: %.2f%n", max / 1e6); - } - - public static void main(String[] args) throws Exception { - // Allow the JDK HttpClient to set a "host" header before anything - // creates an HttpRequest.Builder. JavaHttpClientTransport sets this - // in its static initializer, but we hit a chicken-and-egg problem: - // the IMDS credential provider builds an HttpClient before - // JavaHttpClientTransport ever loads, by which time the "host" - // header restriction is locked in. Setting it here, first thing, - // sidesteps the whole ordering issue. + private static void configureRuntime() { var restricted = System.getProperty("jdk.httpclient.allowRestrictedHeaders"); if (restricted == null || restricted.isEmpty()) { System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host"); } else if (!restricted.contains("host")) { System.setProperty("jdk.httpclient.allowRestrictedHeaders", restricted + ",host"); } - // Force smithy-java's native JSON provider over Jackson. Jackson is - // bundled because some smithy-java modules pull it in transitively; - // its priority (10) outranks the smithy provider (5), so we'd - // silently use Jackson without this. Set before any JsonCodec - // initializes — the provider is selected in a static initializer. + if (System.getProperty("jdk.httpclient.bufsize") == null) { + System.setProperty("jdk.httpclient.bufsize", "65536"); + } + if (System.getProperty("jdk.httpclient.maxframesize") == null) { + System.setProperty("jdk.httpclient.maxframesize", "65536"); + } if (System.getProperty("smithy-java.json-provider") == null) { System.setProperty("smithy-java.json-provider", "smithy"); } - // Silence per-call INFO logging from the rules engine endpoint - // resolver. It logs once per client.build() call, but more - // importantly it formats arguments on every emit even if a downstream - // handler filters them — extra work on the hot path. Bump JUL's - // root level so the System.Logger backend short-circuits. Skip the - // reset when -Dsmithy.bench.debug=true so wire logging stays visible. if (!"true".equals(System.getProperty("smithy.bench.debug"))) { LogManager.getLogManager().reset(); - var rootLogger = Logger.getLogger(""); - rootLogger.setLevel(java.util.logging.Level.WARNING); + Logger.getLogger("").setLevel(java.util.logging.Level.WARNING); } - // Mirror the reference runner's CLI: - // java -jar runner.jar [--client sync|async] - // We only support sync (smithy-java has no async client). The - // CLI argument is accepted but ignored — region is read - // from the workload's actionConfig like every other field. - int idx = 0; - if (args.length > 0 && "--client".equals(args[0])) { - if (args.length < 2) { - fail("Error: --client requires a value (sync or async)"); - } - String mode = args[1]; - if ("async".equals(mode)) { - System.err.println("WARNING: smithy-java does not generate async clients. " - + "Running with the synchronous client; throughput tests will use a thread pool."); - } else if (!"sync".equals(mode)) { - fail("Error: Invalid client mode '" + mode + "'. Valid values are: sync, async"); - } - idx = 2; - } - if (args.length - idx < 2) { - fail("Usage: java -jar smithy-java-e2e-benchmark-runner.jar [--client sync|async] "); - } - var workloadPath = args[idx]; - // args[idx + 1] is the region from the orchestration script; we - // intentionally ignore it (the workload JSON is the source of truth). - var workload = WorkloadConfig.load(workloadPath); - printActiveJsonProvider(); - new WorkloadRunner(workload).run(); } private static void printActiveJsonProvider() { - // Reflectively read JsonSettings.PROVIDER so we can confirm which - // implementation actually got picked, without depending on - // package-private getters. try { var clazz = Class.forName("software.amazon.smithy.java.json.JsonSettings"); var field = clazz.getDeclaredField("PROVIDER"); @@ -370,9 +63,152 @@ private static void printActiveJsonProvider() { System.err.println("Could not determine active JSON provider: " + e); } } +} + + +enum Operation { + S3_PUT("s3-put", false), + S3_GET("s3-get", false), + DDB_PUT("ddb-put", true), + DDB_GET("ddb-get", true); + + final String id; + final boolean sequential; + + Operation(String id, boolean sequential) { + this.id = id; + this.sequential = sequential; + } + + boolean isS3() { + return this == S3_PUT || this == S3_GET; + } + + boolean isDdb() { + return this == DDB_PUT || this == DDB_GET; + } + + static Operation parse(String value) { + var normalized = value.toLowerCase().replace('_', '-'); + return switch (normalized) { + case "s3-put", "s3-upload", "putobject", "upload" -> S3_PUT; + case "s3-get", "s3-download", "getobject", "download" -> S3_GET; + case "ddb-put", "ddb-putitem", "dynamodb-putitem", "putitem" -> DDB_PUT; + case "ddb-get", "ddb-getitem", "dynamodb-getitem", "getitem" -> DDB_GET; + default -> inferFromLegacyPath(normalized); + }; + } + + private static Operation inferFromLegacyPath(String value) { + if (value.contains("s3-upload")) { + return S3_PUT; + } else if (value.contains("s3-download")) { + return S3_GET; + } else if (value.contains("ddb-putitem")) { + return DDB_PUT; + } else if (value.contains("ddb-getitem")) { + return DDB_GET; + } + throw new IllegalArgumentException("Unknown benchmark operation: " + value); + } +} + + +record BenchmarkConfig( + Operation operation, + String region, + String bucketName, + String tableName, + String keyPrefix, + String s3KeyPrefix, + int objectSize, + int dataLength, + int batchActions, + int warmupBatches, + int measurementBatches, + boolean collectMetrics, + int metricsIntervalMs, + boolean ddbCreateTable, + boolean ddbDeleteTable, + long ddbReadCapacityUnits, + long ddbWriteCapacityUnits) { + private static final String DEFAULT_REGION = "us-east-1"; + private static final String DEFAULT_BUCKET = "dowling-bench--use1-az4--x-s3"; + private static final String DEFAULT_TABLE = "benchmark-table"; + private static final String DEFAULT_KEY_PREFIX = "item-"; + private static final String DEFAULT_S3_KEY_PREFIX = "objects/256KiB/"; + private static final int DEFAULT_DDB_ACTIONS = 1000; + private static final int DEFAULT_S3_ACTIONS = 10000; + private static final int DEFAULT_WARMUP_BATCHES = 2; + private static final int DEFAULT_MEASUREMENT_BATCHES = 3; + private static final int DEFAULT_OBJECT_SIZE = 256 * 1024; + private static final int DEFAULT_DATA_LENGTH = 1024; + private static final long DEFAULT_DDB_CAPACITY_UNITS = 5000; + + static BenchmarkConfig parse(String[] args) { + String operation = null; + Map flags = new LinkedHashMap<>(); + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "--operation", "--workload" -> operation = requireValue(args, ++i, args[i - 1]); + case "--client" -> validateClientMode(requireValue(args, ++i, "--client")); + case "--bucket" -> flags.put("bucket", requireValue(args, ++i, "--bucket")); + case "--table" -> flags.put("table", requireValue(args, ++i, "--table")); + case "--region" -> flags.put("region", requireValue(args, ++i, "--region")); + case "--key-prefix" -> flags.put("keyPrefix", requireValue(args, ++i, "--key-prefix")); + case "--s3-key-prefix" -> flags.put("s3KeyPrefix", requireValue(args, ++i, "--s3-key-prefix")); + default -> { + if (args[i].startsWith("--")) { + throw new IllegalArgumentException("Unknown flag: " + args[i]); + } + if (operation != null) { + throw new IllegalArgumentException("Unexpected positional argument: " + args[i]); + } + operation = args[i]; + } + } + } + if (operation == null) { + throw new IllegalArgumentException( + "Usage: java -jar smithy-java-e2e-benchmark-runner.jar " + + "--operation s3-put|s3-get|ddb-put|ddb-get [--bucket ] " + + "[--table ] [--region ]"); + } + + var op = Operation.parse(operation); + int defaultActions = op.isS3() ? DEFAULT_S3_ACTIONS : DEFAULT_DDB_ACTIONS; + return new BenchmarkConfig( + op, + flags.getOrDefault("region", System.getProperty("e2e.region", DEFAULT_REGION)), + flags.getOrDefault("bucket", System.getProperty("e2e.bucket", DEFAULT_BUCKET)), + flags.getOrDefault("table", System.getProperty("e2e.table", DEFAULT_TABLE)), + flags.getOrDefault("keyPrefix", System.getProperty("e2e.keyPrefix", DEFAULT_KEY_PREFIX)), + flags.getOrDefault("s3KeyPrefix", System.getProperty("e2e.s3KeyPrefix", DEFAULT_S3_KEY_PREFIX)), + Integer.getInteger("e2e.object.size", DEFAULT_OBJECT_SIZE), + Integer.getInteger("e2e.data.length", DEFAULT_DATA_LENGTH), + Integer.getInteger("e2e.batch.actions", defaultActions), + Integer.getInteger("e2e.warmup.batches", DEFAULT_WARMUP_BATCHES), + Integer.getInteger("e2e.measurement.batches", DEFAULT_MEASUREMENT_BATCHES), + Boolean.parseBoolean(System.getProperty("e2e.collectMetrics", "true")), + Integer.getInteger("e2e.metrics.interval.ms", 100), + Boolean.parseBoolean(System.getProperty("e2e.ddb.createTable", "true")), + Boolean.parseBoolean(System.getProperty("e2e.ddb.deleteTable", "true")), + Long.getLong("e2e.ddb.readCapacityUnits", DEFAULT_DDB_CAPACITY_UNITS), + Long.getLong("e2e.ddb.writeCapacityUnits", DEFAULT_DDB_CAPACITY_UNITS)); + } - private static void fail(String msg) { - System.err.println(msg); - System.exit(1); + private static void validateClientMode(String mode) { + if ("async".equals(mode)) { + System.err.println("WARNING: smithy-java does not generate async clients. Running synchronous client."); + } else if (!"sync".equals(mode)) { + throw new IllegalArgumentException("Invalid client mode: " + mode); + } + } + + private static String requireValue(String[] args, int i, String flag) { + if (i >= args.length) { + throw new IllegalArgumentException(flag + " requires a value"); + } + return args[i]; } } diff --git a/benchmarks/e2e-benchmarks/workloads/ddb-getitem-1KiB-latency-benchmark.json b/benchmarks/e2e-benchmarks/workloads/ddb-getitem-1KiB-latency-benchmark.json deleted file mode 100644 index accd19bb2d..0000000000 --- a/benchmarks/e2e-benchmarks/workloads/ddb-getitem-1KiB-latency-benchmark.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": 1, - "name": "ddb-getitem-1KiB-latency-benchmark", - "description": "DynamoDB GetItem latency benchmark - measures SDK latency for read operations with 1KiB items executed sequentially", - "service": "dynamodb", - "action": "getitem", - "actionConfig": { - "tableName": "benchmark-table", - "region": "us-east-1", - "keyPrefix": "item-" - }, - "batch": { - "description": "A batch is 1,000 GetItem actions executed sequentially", - "numberOfActions": 1000, - "sequentialExecution": true - }, - "warmup": { - "batches": 2 - }, - "measurement": { - "batches": 3, - "collectMetrics": true, - "metricsInterval": 100 - } -} \ No newline at end of file diff --git a/benchmarks/e2e-benchmarks/workloads/ddb-putitem-1KiB-latency-benchmark.json b/benchmarks/e2e-benchmarks/workloads/ddb-putitem-1KiB-latency-benchmark.json deleted file mode 100644 index ccc28f3de7..0000000000 --- a/benchmarks/e2e-benchmarks/workloads/ddb-putitem-1KiB-latency-benchmark.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": 1, - "name": "ddb-putitem-1KiB-latency-benchmark", - "description": "DynamoDB PutItem latency benchmark - measures SDK latency for write operations executed sequentially.", - "service": "dynamodb", - "action": "putitem", - "actionConfig": { - "description": "Each item has a string partition key 'pk' (format: '') and a binary attribute 'data' with bytes of String type data.", - "tableName": "benchmark-table", - "region": "us-east-1", - "dataLength": 1024, - "keyPrefix": "item-" - }, - "batch": { - "description": "A batch is 1,000 PutItem actions executed sequentially", - "numberOfActions": 1000, - "sequentialExecution": true - }, - "warmup": { - "batches": 2 - }, - "measurement": { - "batches": 3, - "collectMetrics": true, - "metricsInterval": 100 - } -} \ No newline at end of file diff --git a/benchmarks/e2e-benchmarks/workloads/s3-download-256KiB-throughput-benchmark.json b/benchmarks/e2e-benchmarks/workloads/s3-download-256KiB-throughput-benchmark.json deleted file mode 100644 index 4d79494f29..0000000000 --- a/benchmarks/e2e-benchmarks/workloads/s3-download-256KiB-throughput-benchmark.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": 1, - "name": "s3-download-256KiB-throughput-benchmark", - "description": "S3 GetObject throughput benchmark - measures maximum download throughput with 256KiB objects under high concurrency", - "service": "s3", - "action": "download", - "actionConfig": { - "bucketName": "my-benchmark-bucket--use1-az4--x-s3", - "region": "us-east-1", - "objectSize": 262144, - "filesOnDisk": false, - "checksum": null, - "keyPrefix": "objects/256KiB/" - }, - "batch": { - "description": "A batch is 10,000 GetObject actions executed concurrently with SDK's optimal concurrency", - "numberOfActions": 10000, - "sequentialExecution": false - }, - "warmup": { - "batches": 2 - }, - "measurement": { - "batches": 3, - "collectMetrics": true, - "metricsInterval": 100 - } -} \ No newline at end of file diff --git a/benchmarks/e2e-benchmarks/workloads/s3-upload-256KiB-throughput-benchmark.json b/benchmarks/e2e-benchmarks/workloads/s3-upload-256KiB-throughput-benchmark.json deleted file mode 100644 index 63e77ebc62..0000000000 --- a/benchmarks/e2e-benchmarks/workloads/s3-upload-256KiB-throughput-benchmark.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": 1, - "name": "s3-upload-256KiB-throughput-benchmark", - "description": "S3 PutObject throughput benchmark - measures maximum upload throughput with 256KiB objects under high concurrency", - "service": "s3", - "action": "upload", - "actionConfig": { - "bucketName": "my-benchmark-bucket--use1-az4--x-s3", - "region": "us-east-1", - "objectSize": 262144, - "filesOnDisk": false, - "checksum": null, - "keyPrefix": "objects/256KiB/" - }, - "batch": { - "description": "A batch is 10,000 PutObject actions executed concurrently with SDK's optimal concurrency", - "numberOfActions": 10000, - "sequentialExecution": false - }, - "warmup": { - "batches": 2 - }, - "measurement": { - "batches": 3, - "collectMetrics": true, - "metricsInterval": 100 - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/smithy-java.module-conventions.gradle.kts b/buildSrc/src/main/kotlin/smithy-java.module-conventions.gradle.kts index b9afb61d73..00479f6b8e 100644 --- a/buildSrc/src/main/kotlin/smithy-java.module-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/smithy-java.module-conventions.gradle.kts @@ -87,6 +87,3 @@ tasks.jacocoTestReport { html.outputLocation.set(file("${layout.buildDirectory.get()}/reports/jacoco")) } } - -// Ensure integ tests are executed as part of test suite -tasks["test"].finalizedBy("integ") diff --git a/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientCall.java b/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientCall.java index d8fb681e2d..d64f32a585 100644 --- a/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientCall.java +++ b/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientCall.java @@ -7,8 +7,6 @@ import java.util.Map; import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; import software.amazon.smithy.java.auth.api.identity.IdentityResolvers; import software.amazon.smithy.java.client.core.auth.scheme.AuthScheme; import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver; @@ -69,13 +67,13 @@ final class ClientCall a)); + this.supportedAuthSchemes = callConfig.supportedAuthSchemesById(); this.eventStreamWriter = operation.inputEventBuilderSupplier() != null ? ProtocolEventStreamWriter.of(input.getMemberValue(operation.inputStreamMember())) : null; diff --git a/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientConfig.java b/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientConfig.java index 3dc5e84fd3..b8628ba8b4 100644 --- a/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientConfig.java +++ b/client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientConfig.java @@ -27,6 +27,7 @@ import software.amazon.smithy.java.endpoints.EndpointResolver; import software.amazon.smithy.java.logging.InternalLogger; import software.amazon.smithy.java.retries.api.RetryStrategy; +import software.amazon.smithy.model.shapes.ShapeId; /** * An immutable representation of configurations of a {@link Client}. @@ -46,6 +47,7 @@ public final class ClientConfig { private final List interceptors; private final ClientInterceptor interceptorChain; private final List> supportedAuthSchemes; + private final Map> supportedAuthSchemesById; private final AuthSchemeResolver authSchemeResolver; private final List> identityResolvers; private final Context context; @@ -86,6 +88,11 @@ private ClientConfig(Builder builder) { supportedAuthSchemes.add(NO_AUTH_AUTH_SCHEME); supportedAuthSchemes.addAll(builder.supportedAuthSchemes); this.supportedAuthSchemes = Collections.unmodifiableList(supportedAuthSchemes); + var supportedAuthSchemesById = new LinkedHashMap>(); + for (var scheme : supportedAuthSchemes) { + supportedAuthSchemesById.putIfAbsent(scheme.schemeId(), scheme); + } + this.supportedAuthSchemesById = Collections.unmodifiableMap(supportedAuthSchemesById); this.authSchemeResolver = Objects.requireNonNullElse(builder.authSchemeResolver, AuthSchemeResolver.DEFAULT); this.identityResolvers = List.copyOf(builder.identityResolvers); @@ -194,6 +201,10 @@ public ClientInterceptor interceptorChain() { return supportedAuthSchemes; } + Map> supportedAuthSchemesById() { + return supportedAuthSchemesById; + } + /** * @return Resolver to use to resolve the authentication scheme that should be used to sign a request. */ diff --git a/client/client-http-boringssl/build.gradle.kts b/client/client-http-boringssl/build.gradle.kts new file mode 100644 index 0000000000..fe93154a47 --- /dev/null +++ b/client/client-http-boringssl/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + id("smithy-java.module-conventions") +} + +description = "BoringSSL (netty-tcnative) SSLEngine provider for the Smithy native HTTP client" + +extra["displayName"] = "Smithy :: Java :: Client :: HTTP :: BoringSSL" +extra["moduleName"] = "software.amazon.smithy.java.client.http.boringssl" + +dependencies { + // The netty-free TLS seam (ClientSslEngineFactory) lives in http-client; this module is the only + // place io.netty/tcnative types are allowed, keeping the rest of the HTTP stack provider-agnostic. + api(project(":http:http-client")) + implementation(project(":logging")) + + implementation("io.netty:netty-handler:4.2.13.Final") + implementation("io.netty:netty-buffer:4.2.13.Final") + + // netty-tcnative (BoringSSL): base jar carries the Java classes; the native library ships in + // per-platform classifier artifacts. We pull the classifiers for the platforms we build/benchmark + // on (dev: macOS arm64/x64; benchmark + prod: Linux x64/arm64). At runtime Netty loads whichever + // matches the host; the others are inert. tcnative is optional — BoringSslEngineFactory.isAvailable() + // reports false when the native lib is absent, and callers fall back to the JDK provider. + implementation("io.netty:netty-tcnative-boringssl-static:2.0.77.Final") + runtimeOnly("io.netty:netty-tcnative-boringssl-static:2.0.77.Final:osx-aarch_64") + runtimeOnly("io.netty:netty-tcnative-boringssl-static:2.0.77.Final:osx-x86_64") + runtimeOnly("io.netty:netty-tcnative-boringssl-static:2.0.77.Final:linux-x86_64") + runtimeOnly("io.netty:netty-tcnative-boringssl-static:2.0.77.Final:linux-aarch_64") + + testImplementation(project(":codecs:json-codec", configuration = "shadow")) +} diff --git a/client/client-http-boringssl/src/main/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProvider.java b/client/client-http-boringssl/src/main/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProvider.java new file mode 100644 index 0000000000..2173102178 --- /dev/null +++ b/client/client-http-boringssl/src/main/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProvider.java @@ -0,0 +1,180 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.boringssl; + +import io.netty.buffer.ByteBufAllocator; +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.OpenSsl; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.ResourceLeakDetector; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLParameters; +import software.amazon.smithy.java.http.client.connection.ConnectionTransport; +import software.amazon.smithy.java.http.client.connection.SslEngineTransports; +import software.amazon.smithy.java.http.client.connection.TlsConnectionContext; +import software.amazon.smithy.java.http.client.connection.TlsProvider; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * A {@link TlsProvider} backed by netty-tcnative's BoringSSL {@link SSLEngine} + * ({@code ReferenceCountedOpenSslEngine}), whose AES-GCM (VAES/AVX-512 on modern x86-64) is markedly + * cheaper than the JDK {@code SSLEngine}. The engine is a standard {@code javax.net.ssl.SSLEngine}, so + * the connection runs on the built-in {@code SSLEngineTransport} (via {@link SslEngineTransports}) with + * no Netty pipeline, event loop, or {@code SslHandler} — keeping the crypto win without the + * per-connection pipeline overhead. + * + *

This is the only place {@code io.netty}/tcnative types appear in the HTTP client stack; it is + * plugged in through the provider-neutral {@link TlsProvider} seam via + * {@code HttpClient.Builder.tlsProvider(...)}. + * + *

Engine lifecycle

+ * The BoringSSL engine is reference-counted and holds off-heap memory, so each minted engine is paired + * with a releaser that the transport invokes exactly once on connection close. While + * {@code OpenSslEngine} also frees via a finalizer, explicit release avoids finalizer lag and GC + * pressure under high connection churn. + */ +public final class BoringSslTlsProvider implements TlsProvider { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(BoringSslTlsProvider.class); + + static { + // The BoringSSL engine ({@code ReferenceCountedOpenSslEngine}) tracks its pooled off-heap + // buffers through Netty's leak detector, which defaults to SIMPLE: a sampled fraction of + // every buffer allocate/release captures a Throwable stack trace. On this hot transport path + // (driven by SSLEngineTransport, NOT the Netty pipeline) that costs CPU + per-record alloc + // churn with no diagnostic value — and unlike the Netty transport's VtH1Transport, nothing + // else on the smithy+BoringSSL path disables it. Disable unless the operator has explicitly + // chosen a level via either Netty system property. + if (System.getProperty("io.netty.leakDetection.level") == null + && System.getProperty("io.netty.leakDetectionLevel") == null) { + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); + } + } + + private final boolean trustAll; + // OpenSSL only negotiates ALPN when the protocol list is configured on the SslContext at build + // time, but the list arrives per-engine. Contexts are immutable and reusable, so cache one per + // distinct ALPN list (in practice a single client uses one list for its lifetime). + private final ConcurrentHashMap, SslContext> contextsByAlpn = new ConcurrentHashMap<>(); + + /** + * No-arg constructor for {@link java.util.ServiceLoader} discovery (production defaults: + * {@code trustAll=false}). Selected via {@code -Dsmithy-java.tls-provider=software.amazon.smithy.java.client.http.boringssl.BoringSslTlsProvider}. + */ + public BoringSslTlsProvider() { + this(false); + } + + private BoringSslTlsProvider(boolean trustAll) { + this.trustAll = trustAll; + } + + /** + * Create a BoringSSL TLS provider for {@code HttpClient.Builder.tlsProvider(...)}. + * + * @param trustAll when true, trust all server certificates (benchmark/testing only — never in production) + * @return a TLS provider backed by BoringSSL + * @throws IllegalStateException if the native provider is unavailable + */ + public static BoringSslTlsProvider create(boolean trustAll) { + if (!OpenSsl.isAvailable()) { + throw new IllegalStateException( + "netty-tcnative (BoringSSL) is unavailable: " + OpenSsl.unavailabilityCause()); + } + return new BoringSslTlsProvider(trustAll); + } + + /** + * Whether the native BoringSSL provider is loadable on this host. When false, callers should fall + * back to the JDK provider (do not construct this provider). + * + * @return true if netty-tcnative (BoringSSL) is available + */ + @Override + public boolean isAvailable() { + return OpenSsl.isAvailable(); + } + + /** + * @return true if netty-tcnative (BoringSSL) is loadable on this host. + */ + public static boolean available() { + return OpenSsl.isAvailable(); + } + + @Override + public ConnectionTransport connect(TlsConnectionContext context) throws IOException { + SSLEngine engine = newEngine(context.host(), context.port(), context.alpnProtocols()); + return SslEngineTransports.connect(context, engine, releaser(engine)); + } + + @Override + public boolean supportsEpoll() { + // Engine-based: SslEngineTransports consumes the internal epoll channel directly. + return true; + } + + private SslContext contextFor(List alpnProtocols) { + return contextsByAlpn.computeIfAbsent(alpnProtocols, protocols -> { + try { + var builder = SslContextBuilder.forClient().sslProvider(SslProvider.OPENSSL); + if (trustAll) { + builder.trustManager(InsecureTrustManagerFactory.INSTANCE); + } + // netty-tcnative's OpenSSL engine only negotiates ALPN when the protocol list is configured + // on the SslContext at build time; SSLParameters.setApplicationProtocols() on the engine + // afterward is ignored by the OpenSSL provider. NO_ADVERTISE/ACCEPT is the standard client + // ALPN behavior. An empty list builds a context with no ALPN. + if (!protocols.isEmpty()) { + builder.applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + protocols.toArray(new String[0]))); + } + return builder.build(); + } catch (SSLException e) { + throw new IllegalStateException("Failed to build BoringSSL client context", e); + } + }); + } + + // Mint a client-mode BoringSSL engine for host:port with the given ALPN list. Package-private so + // low-level engine tests can exercise the engine directly; production goes through connect(). + SSLEngine newEngine(String host, int port, List alpnProtocols) { + // ALPN must be configured on the SslContext (see contextFor); pick the context matching this + // call's protocol list. newEngine(alloc, host, port) returns a standard SSLEngine in + // jdkCompatibilityMode (one TLS record per wrap, standard BUFFER_OVERFLOW semantics) — exactly + // what SSLEngineTransport's wrap/unwrap loop expects. + List protocols = alpnProtocols == null ? List.of() : List.copyOf(alpnProtocols); + SSLEngine engine = contextFor(protocols).newEngine(ByteBufAllocator.DEFAULT, host, port); + engine.setUseClientMode(true); + + SSLParameters params = engine.getSSLParameters(); + params.setEndpointIdentificationAlgorithm("HTTPS"); + engine.setSSLParameters(params); + return engine; + } + + // The release callback for a minted engine: drops the off-heap reference count exactly once. + static Runnable releaser(SSLEngine engine) { + return () -> { + try { + ReferenceCountUtil.release(engine); + } catch (RuntimeException e) { + LOGGER.debug("Failed to release BoringSSL engine: {}", e.getMessage()); + } + }; + } +} diff --git a/client/client-http-boringssl/src/main/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider b/client/client-http-boringssl/src/main/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider new file mode 100644 index 0000000000..5b4a729c20 --- /dev/null +++ b/client/client-http-boringssl/src/main/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider @@ -0,0 +1 @@ +software.amazon.smithy.java.client.http.boringssl.BoringSslTlsProvider diff --git a/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderTest.java b/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderTest.java new file mode 100644 index 0000000000..86ab71b592 --- /dev/null +++ b/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderTest.java @@ -0,0 +1,432 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.boringssl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import io.netty.handler.ssl.util.SelfSignedCertificate; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * End-to-end coverage for the BoringSSL SSLEngine provider driven through the smithy native + * {@code SSLEngineTransport} (no Netty pipeline). Runs a real HTTPS handshake + request/response + + * body upload + keep-alive reuse against a local {@link HttpsServer} with a self-signed cert. + * + *

Skipped (not failed) when netty-tcnative is unavailable on the host, so the build stays green + * on platforms without the native library. + */ +class BoringSslTlsProviderTest { + + private HttpsServer server; + + @BeforeEach + void requireTcnative() { + assumeTrue(BoringSslTlsProvider.available(), + "netty-tcnative (BoringSSL) not available on this host"); + } + + @AfterEach + void tearDown() { + if (server != null) { + server.stop(0); + } + } + + private void startTlsEchoServer(AtomicInteger requestCount) throws Exception { + var ssc = new SelfSignedCertificate(); + var ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + ks.setKeyEntry("key", ssc.key(), new char[0], new Certificate[] {ssc.cert()}); + var kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, new char[0]); + var sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), null, null); + + server = HttpsServer.create(new InetSocketAddress("127.0.0.1", 0), 0); + server.setHttpsConfigurator(new HttpsConfigurator(sslContext)); + server.createContext("/echo", exchange -> { + requestCount.incrementAndGet(); + byte[] body = exchange.getRequestBody().readAllBytes(); + byte[] resp = (exchange.getRequestMethod() + ":" + new String(body, StandardCharsets.UTF_8)) + .getBytes(StandardCharsets.UTF_8); + exchange.getResponseHeaders().add("content-type", "text/plain"); + exchange.sendResponseHeaders(200, resp.length); + exchange.getResponseBody().write(resp); + exchange.close(); + }); + server.createContext("/raw", exchange -> { + requestCount.incrementAndGet(); + byte[] body = exchange.getRequestBody().readAllBytes(); + exchange.getResponseHeaders().add("content-type", "application/octet-stream"); + exchange.sendResponseHeaders(200, body.length); + exchange.getResponseBody().write(body); + exchange.close(); + }); + // Promises a 100-byte body but sends only headers + nothing, then stalls — the client's body + // read blocks until the watchdog fires (exercises readWithTimeout's deadline path). + server.createContext("/stall", exchange -> { + requestCount.incrementAndGet(); + exchange.getRequestBody().readAllBytes(); + exchange.sendResponseHeaders(200, 100); + try { + Thread.sleep(60_000); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + }); + server.start(); + } + + private HttpClient boringSslClient(int maxConns) { + return boringSslClient(maxConns, null); + } + + private HttpClient boringSslClient(int maxConns, Duration readTimeout) { + var builder = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(maxConns) + .maxConnectionsPerRoute(maxConns) + .tlsProvider(BoringSslTlsProvider.create(true)); // trustAll: self-signed test cert + if (readTimeout != null) { + builder.readTimeout(readTimeout); + } + return builder.build(); + } + + private static HttpRequest put(String uri, String body) { + return HttpRequest.create() + .setMethod("PUT") + .setUri(URI.create(uri)) + .setHttpVersion(HttpVersion.HTTP_1_1) + .setBody(DataStream.ofString(body, "text/plain")) + .toUnmodifiable(); + } + + @Test + void readTimeoutFiresViaWatchdog() throws Exception { + // The server sends response headers then stalls without sending the promised body. The + // blocking-channel body read must be aborted by the shared HashedWheelTimer watchdog (not + // hang), proving readWithTimeout's deadline path works without a per-read Selector. + var requestCount = new AtomicInteger(); + startTlsEchoServer(requestCount); + + try (var client = boringSslClient(1, Duration.ofMillis(500))) { + String uri = "https://127.0.0.1:" + server.getAddress().getPort() + "/stall"; + long start = System.nanoTime(); + var ex = Assertions.assertThrows(java.io.IOException.class, () -> { + HttpResponse response = client.send(put(uri, "x")); + // Force the body read where the stall happens. + try (var b = response.body().asInputStream()) { + b.readAllBytes(); + } + }); + long elapsedMs = (System.nanoTime() - start) / 1_000_000; + // Fired promptly (well under the server's 60s stall), not hung. + Assertions.assertTrue(elapsedMs < 10_000, + "expected timeout to fire promptly, took " + elapsedMs + "ms"); + // The cause chain should mention a read timeout somewhere. + String msg = String.valueOf(ex); + for (Throwable t = ex; t != null; t = t.getCause()) { + msg += " | " + t; + } + Assertions.assertTrue( + msg.toLowerCase().contains("time"), + "expected a timeout-related exception, got: " + msg); + } + } + + @Test + void httpsRequestAndKeepAliveReuse() throws Exception { + var requestCount = new AtomicInteger(); + startTlsEchoServer(requestCount); + + // One connection forces every request after the first to reuse the same TLS session. + try (var client = boringSslClient(1)) { + String uri = "https://127.0.0.1:" + server.getAddress().getPort() + "/echo"; + for (int i = 0; i < 10; i++) { + HttpResponse response = client.send(put(uri, "tls-" + i)); + assertThat(response.statusCode(), equalTo(200)); + try (var b = response.body().asInputStream()) { + assertThat(new String(b.readAllBytes(), StandardCharsets.UTF_8), equalTo("PUT:tls-" + i)); + } + } + assertEquals(10, requestCount.get()); + } + } + + @Test + void httpsLargeBodyRoundTrip() throws Exception { + var requestCount = new AtomicInteger(); + startTlsEchoServer(requestCount); + + byte[] payload = new byte[256 * 1024]; + for (int i = 0; i < payload.length; i++) { + payload[i] = (byte) (i * 31 + 7); + } + + try (var client = boringSslClient(2)) { + String uri = "https://127.0.0.1:" + server.getAddress().getPort() + "/raw"; + for (int attempt = 0; attempt < 3; attempt++) { + HttpRequest request = HttpRequest.create() + .setMethod("PUT") + .setUri(URI.create(uri)) + .setHttpVersion(HttpVersion.HTTP_1_1) + .setBody(DataStream.ofBytes(payload)) + .toUnmodifiable(); + HttpResponse response = client.send(request); + assertThat(response.statusCode(), equalTo(200)); + try (var b = response.body().asInputStream()) { + assertThat(Arrays.equals(b.readAllBytes(), payload), equalTo(true)); + } + } + assertEquals(3, requestCount.get()); + } + } + + @Test + void httpsLargeBodyRoundTripWithLargeReadBuffer() throws Exception { + // Same 256 KiB round-trip, but with a 256 KiB tlsReadBufferSize so a single socketChannel.read + // pulls many TLS records at once and SSLEngineTransport.readAndUnwrap drains them all in one + // pass (compacting netIn once, not per record). This is the multi-record batch-drain path the + // default 16 KiB buffer never exercises; assert byte-exactness across reuse to prove the + // drain-then-compact loop frames every record correctly and leaves no plaintext behind. + var requestCount = new AtomicInteger(); + startTlsEchoServer(requestCount); + + byte[] payload = new byte[256 * 1024]; + for (int i = 0; i < payload.length; i++) { + payload[i] = (byte) (i * 17 + 3); + } + + try (var client = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(1) + .maxConnectionsPerRoute(1) + .tlsReadBufferSize(256 * 1024) + .socketReceiveBufferSize(512 * 1024) + .tlsProvider(BoringSslTlsProvider.create(true)) + .build()) { + String uri = "https://127.0.0.1:" + server.getAddress().getPort() + "/raw"; + for (int attempt = 0; attempt < 3; attempt++) { + HttpRequest request = HttpRequest.create() + .setMethod("PUT") + .setUri(URI.create(uri)) + .setHttpVersion(HttpVersion.HTTP_1_1) + .setBody(DataStream.ofBytes(payload)) + .toUnmodifiable(); + HttpResponse response = client.send(request); + assertThat(response.statusCode(), equalTo(200)); + try (var b = response.body().asInputStream()) { + assertThat(Arrays.equals(b.readAllBytes(), payload), equalTo(true)); + } + } + // One connection reused across all three — each response fully drained and released. + assertEquals(3, requestCount.get()); + } + } + + @Test + void httpsLargeBodyRoundTripWithLargeWriteBuffer() throws Exception { + // Drive the coalescing write path: a 256 KiB body wrapped into ~16 TLS records that + // accumulate in one 256 KiB netOut before a single writeNetOut, instead of one socket write + // per record. The echo server reflects the body, so a byte-exact round-trip proves write() + // framed every coalesced record correctly (no dropped/duplicated bytes at flush boundaries). + var requestCount = new AtomicInteger(); + startTlsEchoServer(requestCount); + + byte[] payload = new byte[256 * 1024]; + for (int i = 0; i < payload.length; i++) { + payload[i] = (byte) (i * 13 + 5); + } + + try (var client = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(1) + .maxConnectionsPerRoute(1) + .tlsWriteBufferSize(256 * 1024) + .socketSendBufferSize(512 * 1024) + .tlsProvider(BoringSslTlsProvider.create(true)) + .build()) { + String uri = "https://127.0.0.1:" + server.getAddress().getPort() + "/raw"; + for (int attempt = 0; attempt < 3; attempt++) { + HttpRequest request = HttpRequest.create() + .setMethod("PUT") + .setUri(URI.create(uri)) + .setHttpVersion(HttpVersion.HTTP_1_1) + .setBody(DataStream.ofBytes(payload)) + .toUnmodifiable(); + HttpResponse response = client.send(request); + assertThat(response.statusCode(), equalTo(200)); + try (var b = response.body().asInputStream()) { + assertThat(Arrays.equals(b.readAllBytes(), payload), equalTo(true)); + } + } + assertEquals(3, requestCount.get()); + } + } + + @Test + void negotiatesH2ViaAlpn() throws Exception { + // Regression: the OpenSSL engine only performs ALPN when the protocol list is configured on the + // SslContext at build time. A client offering [h2, http/1.1] against an h2-capable server must + // negotiate h2, so SSLEngineTransport.negotiatedProtocol() (engine.getApplicationProtocol()) sees it. + assertEquals("h2", negotiatedProtocol(List.of("h2", "http/1.1"), List.of("h2", "http/1.1"))); + } + + @Test + void honorsPerCallAlpnList() throws Exception { + // The factory must advertise exactly the protocols passed to newEngine, not a hardcoded list: + // an http/1.1-only client must negotiate http/1.1 even against an h2-preferring server. + assertEquals("http/1.1", negotiatedProtocol(List.of("http/1.1"), List.of("h2", "http/1.1"))); + } + + /** + * Handshake a BoringSSL client engine (offering {@code clientAlpn}) against a JDK server + * {@link javax.net.ssl.SSLSocket} (offering {@code serverAlpn}) over a real loopback socket, and return + * the client's negotiated ALPN protocol. Using a real socket lets each side block on its peer's flight, + * which is far more robust than an in-memory wrap/unwrap ping-pong. + */ + private static String negotiatedProtocol(List clientAlpn, List serverAlpn) throws Exception { + var ssc = new SelfSignedCertificate(); + var ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + ks.setKeyEntry("key", ssc.key(), new char[0], new Certificate[] {ssc.cert()}); + var kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, new char[0]); + var serverSslContext = SSLContext.getInstance("TLS"); + serverSslContext.init(kmf.getKeyManagers(), null, null); + + try (var listener = (SSLServerSocket) serverSslContext.getServerSocketFactory() + .createServerSocket(0, 1, InetAddress.getLoopbackAddress())) { + int port = listener.getLocalPort(); + var serverParams = listener.getSSLParameters(); + serverParams.setApplicationProtocols(serverAlpn.toArray(new String[0])); + listener.setSSLParameters(serverParams); + + // Server thread: accept and complete the JDK-side handshake (which negotiates ALPN itself). + var serverThread = new Thread(() -> { + try (var s = (SSLSocket) listener.accept()) { + s.startHandshake(); + s.getInputStream().read(); // block until the client closes, keeping the session open + } catch (Exception ignored) { + // server side closing is expected once the client has what it needs + } + }); + serverThread.setDaemon(true); + serverThread.start(); + + SSLEngine client = BoringSslTlsProvider.create(true).newEngine("localhost", port, clientAlpn); + try (var socket = new Socket(InetAddress.getLoopbackAddress(), port)) { + driveClientHandshake(client, socket); + return client.getApplicationProtocol(); + } finally { + BoringSslTlsProvider.releaser(client).run(); + } + } + } + + /** Canonical blocking SSLEngine handshake loop, driving {@code engine} over {@code socket}. */ + private static void driveClientHandshake(SSLEngine engine, Socket socket) + throws Exception { + var in = socket.getInputStream(); + var out = socket.getOutputStream(); + int pkt = engine.getSession().getPacketBufferSize(); + ByteBuffer netOut = ByteBuffer.allocate(pkt); + ByteBuffer netIn = ByteBuffer.allocate(pkt); + ByteBuffer app = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); + byte[] buf = new byte[pkt]; + + engine.beginHandshake(); + var status = engine.getHandshakeStatus(); + while (status != SSLEngineResult.HandshakeStatus.FINISHED + && status != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + switch (status) { + case NEED_WRAP -> { + netOut.clear(); + var r = engine.wrap(ByteBuffer.allocate(0), netOut); + status = r.getHandshakeStatus(); + netOut.flip(); + while (netOut.hasRemaining()) { + out.write(buf, 0, copyOut(netOut, buf)); + } + out.flush(); + } + case NEED_UNWRAP -> { + int n = in.read(buf); + if (n < 0) { + throw new SSLException("peer closed during handshake"); + } + netIn.put(buf, 0, n); + netIn.flip(); + var s = SSLEngineResult.Status.OK; + do { + app.clear(); + var r = engine.unwrap(netIn, app); + status = r.getHandshakeStatus(); + s = r.getStatus(); + runTasks(engine); + if (status == SSLEngineResult.HandshakeStatus.NEED_TASK) { + status = engine.getHandshakeStatus(); + } + } while (s == SSLEngineResult.Status.OK && netIn.hasRemaining() + && status == SSLEngineResult.HandshakeStatus.NEED_UNWRAP); + netIn.compact(); + } + case NEED_TASK -> { + runTasks(engine); + status = engine.getHandshakeStatus(); + } + default -> throw new IllegalStateException("Unexpected handshake status: " + status); + } + } + } + + private static int copyOut(ByteBuffer src, byte[] buf) { + int n = Math.min(src.remaining(), buf.length); + src.get(buf, 0, n); + return n; + } + + private static void runTasks(SSLEngine engine) { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + } +} diff --git a/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderUnitTest.java b/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderUnitTest.java new file mode 100644 index 0000000000..c00bc7b62f --- /dev/null +++ b/client/client-http-boringssl/src/test/java/software/amazon/smithy/java/client/http/boringssl/BoringSslTlsProviderUnitTest.java @@ -0,0 +1,23 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.boringssl; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit checks that need no native library (so they run on every host, unlike the handshake tests). + */ +class BoringSslTlsProviderUnitTest { + + @Test + void supportsEpoll() { + // Engine-based provider: it consumes the internal epoll channel via SslEngineTransports, so the + // client may use the epoll backend for it (no-arg ctor avoids any native context build). + assertTrue(new BoringSslTlsProvider().supportsEpoll()); + } +} diff --git a/client/client-http-smithy/build.gradle.kts b/client/client-http-smithy/build.gradle.kts new file mode 100644 index 0000000000..d5f3c9a756 --- /dev/null +++ b/client/client-http-smithy/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("smithy-java.module-conventions") +} + +description = "Client transport using Smithy's native HTTP client with full HTTP/2 bidirectional streaming" + +extra["displayName"] = "Smithy :: Java :: Client :: HTTP :: Smithy" +extra["moduleName"] = "software.amazon.smithy.java.client.http.smithy" + +dependencies { + api(project(":client:client-http")) + api(project(":http:http-client")) + implementation(project(":logging")) +} diff --git a/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransport.java b/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransport.java new file mode 100644 index 0000000000..1fa5158948 --- /dev/null +++ b/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransport.java @@ -0,0 +1,133 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.smithy; + +import java.io.IOException; +import software.amazon.smithy.java.client.core.ClientTransport; +import software.amazon.smithy.java.client.core.ClientTransportFactory; +import software.amazon.smithy.java.client.core.MessageExchange; +import software.amazon.smithy.java.client.http.HttpContext; +import software.amazon.smithy.java.client.http.HttpMessageExchange; +import software.amazon.smithy.java.context.Context; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.RequestOptions; + +/** + * A client transport using Smithy's native blocking HTTP client with full HTTP/2 bidirectional streaming. + * + *

Unlike the JDK-based transport, this transport supports true bidirectional streaming over HTTP/2: + * the request body can be written concurrently with reading the response body. For HTTP/1.1, the request + * body is fully sent before the response is returned. + */ +public final class SmithyHttpClientTransport implements ClientTransport { + + private final HttpClient client; + + /** + * Create a transport with default settings. + */ + public SmithyHttpClientTransport() { + this(HttpClient.builder().build()); + } + + /** + * Create a transport with the given HTTP client. + * + * @param client the Smithy HTTP client to use + */ + public SmithyHttpClientTransport(HttpClient client) { + this.client = client; + } + + @Override + public MessageExchange messageExchange() { + return HttpMessageExchange.INSTANCE; + } + + @Override + public HttpResponse send(Context context, HttpRequest request) { + try { + var options = RequestOptions.builder() + .requestTimeout(context.get(HttpContext.HTTP_REQUEST_TIMEOUT)) + .build(); + return client.send(request, options); + } catch (Exception e) { + throw ClientTransport.remapExceptions(e); + } + } + + @Override + public void close() throws IOException { + client.close(); + } + + public static final class Factory implements ClientTransportFactory { + @Override + public String name() { + return "http-smithy"; + } + + @Override + public byte priority() { + return 1; + } + + @Override + public SmithyHttpClientTransport createTransport(Document node, Document pluginSettings) { + var config = new SmithyHttpTransportConfig().fromDocument(pluginSettings.asStringMap() + .getOrDefault("httpConfig", Document.EMPTY_MAP)); + config.fromDocument(node); + + var builder = HttpClient.builder(); + + if (config.requestTimeout() != null) { + builder.requestTimeout(config.requestTimeout()); + } + if (config.maxConnections() != null) { + builder.maxTotalConnections(config.maxConnections()); + // If maxConnectionsPerRoute is not explicitly set, default it to maxConnections + // for back-compat with prior behavior. + if (config.maxConnectionsPerRoute() == null) { + builder.maxConnectionsPerRoute(config.maxConnections()); + } + } + if (config.maxConnectionsPerRoute() != null) { + builder.maxConnectionsPerRoute(config.maxConnectionsPerRoute()); + } + if (config.socketReceiveBufferSize() != null) { + builder.socketReceiveBufferSize(config.socketReceiveBufferSize()); + } + if (config.socketSendBufferSize() != null) { + builder.socketSendBufferSize(config.socketSendBufferSize()); + } + if (config.h2StreamsPerConnection() != null) { + builder.h2StreamsPerConnection(config.h2StreamsPerConnection()); + } + if (config.h2InitialWindowSize() != null) { + builder.h2InitialWindowSize(config.h2InitialWindowSize()); + } + if (config.connectTimeout() != null) { + builder.connectTimeout(config.connectTimeout()); + } + if (config.maxIdleTime() != null) { + builder.maxIdleTime(config.maxIdleTime()); + } + if (config.httpVersionPolicy() != null) { + builder.httpVersionPolicy(config.httpVersionPolicy()); + } + + return new SmithyHttpClientTransport(builder.build()); + } + + @Override + public MessageExchange messageExchange() { + return HttpMessageExchange.INSTANCE; + } + } +} diff --git a/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpTransportConfig.java b/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpTransportConfig.java new file mode 100644 index 0000000000..813a64f2be --- /dev/null +++ b/client/client-http-smithy/src/main/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpTransportConfig.java @@ -0,0 +1,160 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.smithy; + +import java.time.Duration; +import software.amazon.smithy.java.client.http.HttpTransportConfig; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; + +/** + * Transport configuration for the Smithy HTTP client, extending common settings + * with connection pool and HTTP/2 tuning options. + */ +public final class SmithyHttpTransportConfig extends HttpTransportConfig { + + private Integer maxConnections; + private Integer maxConnectionsPerRoute; + private Duration maxIdleTime; + private Integer h2StreamsPerConnection; + private Integer h2InitialWindowSize; + private HttpVersionPolicy httpVersionPolicy; + private Integer socketReceiveBufferSize; + private Integer socketSendBufferSize; + + public Integer maxConnections() { + return maxConnections; + } + + public SmithyHttpTransportConfig maxConnections(int maxConnections) { + this.maxConnections = maxConnections; + return this; + } + + /** + * Maximum idle connections retained per route (host+port+proxy). When unset, the route limit + * defaults to {@link #maxConnections}. + */ + public Integer maxConnectionsPerRoute() { + return maxConnectionsPerRoute; + } + + public SmithyHttpTransportConfig maxConnectionsPerRoute(int maxConnectionsPerRoute) { + this.maxConnectionsPerRoute = maxConnectionsPerRoute; + return this; + } + + /** + * SO_RCVBUF for new connection sockets. Larger values help low-concurrency throughput on + * high-bandwidth links; smaller values bound per-connection bufferbloat at high concurrency. + * Unset or {@code -1} defers to the kernel's autotune. See + * {@code HttpConnectionPoolBuilder#socketReceiveBufferSize(int)} for full guidance. + */ + public Integer socketReceiveBufferSize() { + return socketReceiveBufferSize; + } + + public SmithyHttpTransportConfig socketReceiveBufferSize(int bytes) { + this.socketReceiveBufferSize = bytes; + return this; + } + + /** + * SO_SNDBUF for new connection sockets. Unset or {@code -1} defers to the kernel's autotune. + */ + public Integer socketSendBufferSize() { + return socketSendBufferSize; + } + + public SmithyHttpTransportConfig socketSendBufferSize(int bytes) { + this.socketSendBufferSize = bytes; + return this; + } + + public Duration maxIdleTime() { + return maxIdleTime; + } + + public SmithyHttpTransportConfig maxIdleTime(Duration maxIdleTime) { + this.maxIdleTime = maxIdleTime; + return this; + } + + public Integer h2StreamsPerConnection() { + return h2StreamsPerConnection; + } + + public SmithyHttpTransportConfig h2StreamsPerConnection(int h2StreamsPerConnection) { + this.h2StreamsPerConnection = h2StreamsPerConnection; + return this; + } + + public Integer h2InitialWindowSize() { + return h2InitialWindowSize; + } + + public SmithyHttpTransportConfig h2InitialWindowSize(int h2InitialWindowSize) { + this.h2InitialWindowSize = h2InitialWindowSize; + return this; + } + + public HttpVersionPolicy httpVersionPolicy() { + return httpVersionPolicy; + } + + public SmithyHttpTransportConfig httpVersionPolicy(HttpVersionPolicy httpVersionPolicy) { + this.httpVersionPolicy = httpVersionPolicy; + return this; + } + + @Override + public SmithyHttpTransportConfig fromDocument(Document doc) { + super.fromDocument(doc); + var config = doc.asStringMap(); + + var maxConns = config.get("maxConnections"); + if (maxConns != null) { + this.maxConnections = maxConns.asInteger(); + } + + var maxConnsPerRoute = config.get("maxConnectionsPerRoute"); + if (maxConnsPerRoute != null) { + this.maxConnectionsPerRoute = maxConnsPerRoute.asInteger(); + } + + var recvBuf = config.get("socketReceiveBufferSize"); + if (recvBuf != null) { + this.socketReceiveBufferSize = recvBuf.asInteger(); + } + + var sendBuf = config.get("socketSendBufferSize"); + if (sendBuf != null) { + this.socketSendBufferSize = sendBuf.asInteger(); + } + + var idle = config.get("maxIdleTimeMs"); + if (idle != null) { + this.maxIdleTime = Duration.ofMillis(idle.asLong()); + } + + var h2Streams = config.get("h2StreamsPerConnection"); + if (h2Streams != null) { + this.h2StreamsPerConnection = h2Streams.asInteger(); + } + + var h2Window = config.get("h2InitialWindowSize"); + if (h2Window != null) { + this.h2InitialWindowSize = h2Window.asInteger(); + } + + var versionPolicy = config.get("httpVersionPolicy"); + if (versionPolicy != null) { + this.httpVersionPolicy = HttpVersionPolicy.valueOf(versionPolicy.asString()); + } + + return this; + } +} diff --git a/client/client-http-smithy/src/main/resources/META-INF/services/software.amazon.smithy.java.client.core.ClientTransportFactory b/client/client-http-smithy/src/main/resources/META-INF/services/software.amazon.smithy.java.client.core.ClientTransportFactory new file mode 100644 index 0000000000..eaf61a53a0 --- /dev/null +++ b/client/client-http-smithy/src/main/resources/META-INF/services/software.amazon.smithy.java.client.core.ClientTransportFactory @@ -0,0 +1 @@ +software.amazon.smithy.java.client.http.smithy.SmithyHttpClientTransport$Factory diff --git a/client/client-http-smithy/src/test/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransportTest.java b/client/client-http-smithy/src/test/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransportTest.java new file mode 100644 index 0000000000..1d8132266e --- /dev/null +++ b/client/client-http-smithy/src/test/java/software/amazon/smithy/java/client/http/smithy/SmithyHttpClientTransportTest.java @@ -0,0 +1,80 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http.smithy; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.client.http.HttpMessageExchange; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; + +class SmithyHttpClientTransportTest { + + @Test + void defaultConstructorCreatesTransport() { + var transport = new SmithyHttpClientTransport(); + + assertEquals(HttpMessageExchange.INSTANCE, transport.messageExchange()); + } + + @Test + void factorySettings() { + var factory = new SmithyHttpClientTransport.Factory(); + + assertEquals("http-smithy", factory.name()); + assertEquals(HttpMessageExchange.INSTANCE, factory.messageExchange()); + } + + @Test + void configParsesAllFields() { + var config = new SmithyHttpTransportConfig().fromDocument(Document.of(Map.of( + "requestTimeoutMs", + Document.of(5000), + "connectTimeoutMs", + Document.of(3000), + "maxConnections", + Document.of(50), + "maxIdleTimeMs", + Document.of(60000), + "h2StreamsPerConnection", + Document.of(200), + "h2InitialWindowSize", + Document.of(1048576), + "httpVersionPolicy", + Document.of("H2C_PRIOR_KNOWLEDGE")))); + + assertEquals(5000, config.requestTimeout().toMillis()); + assertEquals(3000, config.connectTimeout().toMillis()); + assertEquals(50, config.maxConnections()); + assertEquals(60000, config.maxIdleTime().toMillis()); + assertEquals(200, config.h2StreamsPerConnection()); + assertEquals(1048576, config.h2InitialWindowSize()); + assertEquals(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE, config.httpVersionPolicy()); + } + + @Test + void configHandlesMissingHttpKey() { + var config = new SmithyHttpTransportConfig().fromDocument(Document.of(Map.of())); + + assertNull(config.requestTimeout()); + assertNull(config.maxConnections()); + } + + @Test + void factoryCreatesTransportWithVersionPolicy() { + var factory = new SmithyHttpClientTransport.Factory(); + + assertDoesNotThrow(() -> { + factory.createTransport(Document.of(Map.of( + "httpVersionPolicy", + Document.of("H2C_PRIOR_KNOWLEDGE"))), Document.EMPTY_MAP); + }); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientReplayableByteBufferPublisher.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientReplayableByteBufferPublisher.java new file mode 100644 index 0000000000..55fe31a52f --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientReplayableByteBufferPublisher.java @@ -0,0 +1,55 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import java.net.http.HttpRequest; +import java.nio.ByteBuffer; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A {@link HttpRequest.BodyPublisher} that publishes an in-memory request body in a single {@code onNext} call. + * + *

Used as a fast path for request bodies that are both replayable and already backed by a {@link ByteBuffer}. + * Why not use {@link HttpRequest.BodyPublishers#ofByteArray(byte[])}? -- requires a {@code byte[]}. + * Why not use {@link HttpRequest.BodyPublishers#fromPublisher(Flow.Publisher, long)}? -- add adds a subscription + * state-machine hop and requires the upstream publisher to handle backpressure properly per subscribe. For a single + * in-memory body that's all wasted overhead. + */ +final class JavaHttpClientReplayableByteBufferPublisher implements HttpRequest.BodyPublisher { + private final ByteBuffer body; + + JavaHttpClientReplayableByteBufferPublisher(ByteBuffer body) { + this.body = body.asReadOnlyBuffer(); + } + + @Override + public long contentLength() { + return body.remaining(); + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + subscriber.onSubscribe(new Flow.Subscription() { + private final AtomicBoolean completed = new AtomicBoolean(); + + @Override + public void request(long n) { + if (n <= 0 || !completed.compareAndSet(false, true)) { + return; + } else { + subscriber.onNext(body.duplicate()); + subscriber.onComplete(); + } + } + + @Override + public void cancel() { + completed.set(true); + } + }); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientResponseBodySubscriber.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientResponseBodySubscriber.java new file mode 100644 index 0000000000..2ab7d695b3 --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientResponseBodySubscriber.java @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import java.net.http.HttpHeaders; +import java.net.http.HttpResponse; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Flow; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Response body subscriber used for streaming (large or unknown-length) responses. + * + *

Chosen by {@link JavaHttpClientTransport}'s body handler when the small-body fast path + * ({@link JavaHttpClientSmallBodySubscriber}) does not apply — i.e., when {@code Content-Length} + * is missing or exceeds the small-body threshold. Unlike the small-body path, this subscriber + * returns its {@link DataStream} immediately from {@link #getBody()} rather than + * waiting for {@code onComplete}, so the caller can start reading bytes as they arrive on the + * wire. + * + *

The subscriber is a thin adapter over {@link JavaHttpClientStreamingDataStream}, which + * holds the buffer deque and coordinates the producer (this subscriber) with the consumer + * (the {@link java.io.InputStream} returned by the caller). Callback responsibilities: + *

    + *
  • {@code onSubscribe} — register the subscription with the DataStream so close() can + * cancel it, then request everything (JDK HttpClient paces delivery at the socket + * level, so unbounded demand is safe).
  • + *
  • {@code onNext(List)} — publish the whole batch in one lock acquisition on the + * DataStream, reducing per-buffer overhead compared to one call per {@code ByteBuffer}.
  • + *
  • {@code onError} / {@code onComplete} — terminate the DataStream so a parked reader + * wakes and observes end-of-stream (with an exception or cleanly).
  • + *
+ */ +final class JavaHttpClientResponseBodySubscriber implements HttpResponse.BodySubscriber { + private final JavaHttpClientStreamingDataStream stream; + private final CompletionStage body; + + JavaHttpClientResponseBodySubscriber(HttpHeaders headers) { + this.stream = new JavaHttpClientStreamingDataStream( + headers.firstValue("content-type").orElse(null), + headers.firstValueAsLong("content-length").orElse(-1L)); + // The body is handed to the caller as soon as headers are available; bytes stream + // asynchronously into `stream` afterwards. + this.body = CompletableFuture.completedFuture(stream); + } + + @Override + public CompletionStage getBody() { + return body; + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + stream.setSubscription(subscription); + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(List item) { + stream.enqueueBatch(item); + } + + @Override + public void onError(Throwable throwable) { + stream.fail(throwable); + } + + @Override + public void onComplete() { + stream.complete(); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientSmallBodySubscriber.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientSmallBodySubscriber.java new file mode 100644 index 0000000000..58e6984532 --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientSmallBodySubscriber.java @@ -0,0 +1,91 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import java.net.http.HttpHeaders; +import java.net.http.HttpResponse; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Flow; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Response body subscriber optimized for small responses with a known {@code Content-Length}. + * + *

Chosen by {@link JavaHttpClientTransport}'s body handler when the response's declared + * content length is non-negative and within the small-body threshold. It allocates the exact + * final {@code byte[]} up front (sized from Content-Length), copies each arriving chunk into + * that array, and completes with a {@link DataStream#ofBytes(byte[], String)} when the stream + * ends. + * + *

Rationale: for small bodies the in-memory round-trip through a {@code byte[]} is cheaper + * than the producer/consumer hand-off machinery of + * {@link JavaHttpClientStreamingDataStream}. The caller also gets a replayable, + * known-length {@link DataStream}, which downstream consumers (JSON codecs, signing plugins, + * etc.) can read multiple times without buffering. + * + *

Correctness notes: + *

    + *
  • Content-Length is advisory. If the server sends fewer bytes than advertised, the + * array is copied to a shorter one in {@link #onComplete}. If the server sends more, + * {@code ByteBuffer.get} will fail with {@link java.nio.BufferOverflowException} + * propagated via {@link #onError}. This matches the JDK HttpClient's own behavior for + * mismatched content lengths.
  • + *
  • Threading: all callbacks are invoked on the JDK HttpClient's executor thread, in + * subscription order, so no synchronization is needed between {@code onSubscribe}, + * {@code onNext}, {@code onError}, and {@code onComplete}.
  • + *
+ */ +final class JavaHttpClientSmallBodySubscriber implements HttpResponse.BodySubscriber { + private final String contentType; + private final byte[] bytes; + private int position; + private final CompletableFuture body = new CompletableFuture<>(); + + JavaHttpClientSmallBodySubscriber(HttpHeaders headers, int contentLength) { + this.contentType = headers.firstValue("content-type").orElse(null); + // Math.max guards against a negative Content-Length header (malformed server). + this.bytes = new byte[Math.max(contentLength, 0)]; + } + + @Override + public CompletionStage getBody() { + return body; + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + // Request everything at once; the JDK HttpClient implements Flow backpressure at the + // socket level, so signalling Long.MAX_VALUE here does not actually cause unbounded + // memory use — the wire only delivers what fits in the advertised content length. + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(List item) { + for (ByteBuffer buffer : item) { + int remaining = buffer.remaining(); + buffer.get(bytes, position, remaining); + position += remaining; + } + } + + @Override + public void onError(Throwable throwable) { + body.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + // If the server sent less than Content-Length, hand out a right-sized array rather + // than exposing uninitialized tail bytes to the caller. + byte[] result = position == bytes.length ? bytes : Arrays.copyOf(bytes, position); + body.complete(DataStream.ofBytes(result, contentType)); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingDataStream.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingDataStream.java new file mode 100644 index 0000000000..ee6f53c33a --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingDataStream.java @@ -0,0 +1,378 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.concurrent.Flow; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * A streaming {@link DataStream} that receives {@link ByteBuffer} chunks from a + * {@link java.net.http.HttpResponse.BodySubscriber} and delivers their bytes to a + * caller thread via {@link InputStream}. + * + *

Uses a single {@link ReentrantLock} + {@link Condition} plus an internal + * {@link ArrayDeque} to coordinate producer and consumer. Compared to a plain + * {@link java.util.concurrent.LinkedBlockingQueue}, this: + *

    + *
  • Takes ONE lock per {@code onNext(List)} batch (instead of one per buffer).
  • + *
  • Lets the consumer drain multiple buffers from the deque under a single lock + * acquisition rather than re-locking for each.
  • + *
  • Avoids LBQ's per-node allocation; ArrayDeque uses a small backing array.
  • + *
+ * + *

Threading model: producer is the JDK HttpClient's subscriber callback thread + * (from the {@code Executor} configured on the {@code HttpClient}). Consumer is the + * caller thread that calls {@link InputStream#read}. Either may invoke {@link #close} + * concurrently. + */ +final class JavaHttpClientStreamingDataStream implements DataStream { + + private final ReentrantLock lock = new ReentrantLock(); + private final Condition ready = lock.newCondition(); + // Deque of ByteBuffer chunks awaiting consumption. Guarded by lock. + private final Deque chunks = new ArrayDeque<>(); + + private final String contentType; + private final long contentLength; + + // Producer state (all guarded by lock except where noted): + private Throwable failure; + private boolean endOfStream; + + // Subscription is written once from onSubscribe, read from close(). + private volatile Flow.Subscription subscription; + + // Consumer state (set only from consumer thread): + private volatile boolean consumed; + private volatile boolean closed; + + JavaHttpClientStreamingDataStream(String contentType, long contentLength) { + this.contentType = contentType; + this.contentLength = contentLength; + } + + @Override + public long contentLength() { + return contentLength; + } + + @Override + public String contentType() { + return contentType; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return !consumed; + } + + @Override + public InputStream asInputStream() { + if (consumed) { + throw new IllegalStateException("Response body is not replayable and has already been consumed"); + } + consumed = true; + return new JavaHttpClientStreamingInputStream(this); + } + + @Override + public void close() { + if (closed) { + return; + } + closed = true; + var current = subscription; + if (current != null) { + current.cancel(); + } + lock.lock(); + try { + endOfStream = true; + chunks.clear(); + ready.signal(); + } finally { + lock.unlock(); + } + } + + // ---- Producer API (called from subscriber callbacks) ---- + + void setSubscription(Flow.Subscription subscription) { + this.subscription = subscription; + if (closed) { + subscription.cancel(); + } + } + + /** + * Append a batch of buffers in one lock acquisition. + */ + void enqueueBatch(List batch) { + lock.lock(); + try { + if (endOfStream) { + return; + } + for (ByteBuffer buffer : batch) { + if (buffer.hasRemaining()) { + chunks.add(buffer.asReadOnlyBuffer()); + } + } + ready.signal(); + } finally { + lock.unlock(); + } + } + + void fail(Throwable throwable) { + lock.lock(); + try { + if (endOfStream) { + return; + } + failure = throwable; + endOfStream = true; + ready.signal(); + } finally { + lock.unlock(); + } + } + + void complete() { + lock.lock(); + try { + if (endOfStream) { + return; + } + endOfStream = true; + ready.signal(); + } finally { + lock.unlock(); + } + } + + // ---- Consumer API (called from InputStream.read) ---- + + /** + * Return a non-blocking snapshot of the number of bytes currently buffered and ready to be + * consumed without blocking. Used to back {@link InputStream#available()}. + */ + int availableBytes() { + lock.lock(); + try { + long sum = 0; + for (ByteBuffer chunk : chunks) { + sum += chunk.remaining(); + if (sum >= Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + } + return (int) sum; + } finally { + lock.unlock(); + } + } + + /** + * Advance the read position by up to {@code n} bytes, blocking once for data like + * {@link #readInto} if the deque is empty. Returns the number of bytes actually skipped, + * which may be less than {@code n}, including 0 at end-of-stream. + */ + long skipBytes(long n) throws IOException { + if (n <= 0) { + return 0; + } + lock.lock(); + try { + while (chunks.isEmpty() && !endOfStream) { + try { + ready.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for response body data", e); + } + } + long skipped = 0; + while (skipped < n) { + ByteBuffer head = chunks.peek(); + if (head == null) { + break; + } + int remaining = head.remaining(); + if (remaining == 0) { + chunks.poll(); + continue; + } + long toSkip = Math.min((long) remaining, n - skipped); + head.position(head.position() + (int) toSkip); + skipped += toSkip; + if (!head.hasRemaining()) { + chunks.poll(); + } + } + if (skipped == 0 && failure != null) { + throw new IOException("Failed receiving response body", failure); + } + return skipped; + } finally { + lock.unlock(); + } + } + + /** + * Sentinel returned by {@link #writeNextChunkTo} to request that the caller allocate a + * scratch buffer. Using a sentinel avoids allocating a scratch buffer for streams whose + * chunks are array-backed and can be written directly. + */ + static final int SCRATCH_NEEDED = -2; + + /** + * Write the next queued chunk (if any) to {@code out}. Blocks until a chunk is available, + * the stream ends, or an error is signalled. Writes are performed without the + * internal lock held so a slow {@link OutputStream} does not block the producer. + * + *

If the next chunk is array-backed ({@link ByteBuffer#hasArray()}), its bytes are + * written directly from the backing array (zero intermediate copy). Otherwise, if + * {@code scratch} is non-null, the chunk is drained into {@code scratch} before writing; + * if {@code scratch} is null, {@link #SCRATCH_NEEDED} is returned so the caller can + * allocate one on demand. This lets callers avoid a scratch allocation entirely when + * every chunk is array-backed. + * + * @return bytes written from the popped chunk, {@code -1} at end-of-stream, or + * {@link #SCRATCH_NEEDED} when a scratch buffer is required and none was supplied. + * @throws IOException if the producer signalled a failure, or {@code out.write} throws. + */ + int writeNextChunkTo(OutputStream out, byte[] scratch) throws IOException { + ByteBuffer chunk; + lock.lock(); + try { + while (true) { + // Skip drained chunks to find the first with bytes. + ByteBuffer head = chunks.peek(); + while (head != null && !head.hasRemaining()) { + chunks.poll(); + head = chunks.peek(); + } + if (head != null) { + // If not array-backed and caller has no scratch buffer, punt back to them + // without dequeuing so they can allocate once and retry. + if (!head.hasArray() && scratch == null) { + return SCRATCH_NEEDED; + } + chunk = chunks.poll(); + break; + } + if (endOfStream) { + if (failure != null) { + throw new IOException("Failed receiving response body", failure); + } + return -1; + } + try { + ready.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for response body data", e); + } + } + } finally { + lock.unlock(); + } + + // Write outside the lock so a slow OutputStream does not stall the producer. + int written; + if (chunk.hasArray()) { + int position = chunk.position(); + int remaining = chunk.remaining(); + out.write(chunk.array(), chunk.arrayOffset() + position, remaining); + chunk.position(position + remaining); + written = remaining; + } else { + int remaining = chunk.remaining(); + int toWrite = Math.min(remaining, scratch.length); + chunk.get(scratch, 0, toWrite); + out.write(scratch, 0, toWrite); + written = toWrite; + // If the chunk still has bytes (larger than scratch), push it back for the next call. + if (chunk.hasRemaining()) { + lock.lock(); + try { + chunks.addFirst(chunk); + } finally { + lock.unlock(); + } + } + } + return written; + } + + /** + * Read up to {@code len} bytes into {@code b}, blocking until data is available, + * the stream ends, or an error is signalled. Drains as many queued chunks as fit + * in {@code b} in a single lock acquisition. + * + * @return number of bytes read, or -1 on end-of-stream + */ + int readInto(byte[] b, int off, int len) throws IOException { + lock.lock(); + try { + // Wait for something to consume. + while (chunks.isEmpty() && !endOfStream) { + try { + ready.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for response body data", e); + } + } + + // Drain up to len bytes from the head of the chunk deque. + int total = 0; + while (total < len) { + ByteBuffer head = chunks.peek(); + if (head == null) { + break; + } + int remaining = head.remaining(); + if (remaining == 0) { + chunks.poll(); + continue; + } + int toCopy = Math.min(remaining, len - total); + head.get(b, off + total, toCopy); + total += toCopy; + if (!head.hasRemaining()) { + chunks.poll(); + } + } + + if (total > 0) { + return total; + } + // total == 0 implies chunks was empty AND endOfStream is true. + if (failure != null) { + throw new IOException("Failed receiving response body", failure); + } + return -1; + } finally { + lock.unlock(); + } + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStream.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStream.java new file mode 100644 index 0000000000..4114023a64 --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStream.java @@ -0,0 +1,183 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Objects; + +/** + * {@link InputStream} facade over a {@link JavaHttpClientStreamingDataStream}, exposed to + * callers via {@link software.amazon.smithy.java.io.datastream.DataStream#asInputStream()}. + * + *

The class is intentionally small: buffering, synchronization, and producer/consumer + * coordination all live on the backing {@link JavaHttpClientStreamingDataStream}. This class + * adds only things that belong on the {@code InputStream} API surface: + *

    + *
  • {@link #transferTo(OutputStream)} — writes chunks straight from the underlying + * {@link java.nio.ByteBuffer}s to the target {@code OutputStream}, releasing the + * internal lock while {@code write} runs. Allocates a scratch byte[] lazily, only if a + * non-array-backed chunk is encountered.
  • + *
  • {@link #readAllBytes()} and {@link #readNBytes(int)} — when content-length is known, + * allocate the exact-sized result array once rather than going through {@link + * InputStream}'s default growable implementation.
  • + *
  • {@link #available()} and {@link #skip(long)} — delegate to cheap operations on the + * backing stream.
  • + *
+ * + *

{@link #bytesRead} is maintained across every consumption path so that content-length- + * aware allocations in {@code readAllBytes} / {@code readNBytes} stay correct if the caller + * mixes read forms (e.g., reads some bytes, then calls {@code readAllBytes}). + */ +final class JavaHttpClientStreamingInputStream extends InputStream { + + /** Size of the reusable scratch buffer used by {@link #transferTo(OutputStream)} when chunks are not array-backed. */ + private static final int TRANSFER_SCRATCH_SIZE = 16 * 1024; + + private final JavaHttpClientStreamingDataStream stream; + + /** Number of bytes returned to the caller so far. Used by {@link #readAllBytes()} when content-length is known. */ + private long bytesRead; + + JavaHttpClientStreamingInputStream(JavaHttpClientStreamingDataStream stream) { + this.stream = stream; + } + + @Override + public int read() throws IOException { + byte[] one = new byte[1]; + int n = read(one, 0, 1); + return n < 0 ? -1 : one[0] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { + return 0; + } + int n = stream.readInto(b, off, len); + if (n > 0) { + bytesRead += n; + } + return n; + } + + @Override + public int available() { + return stream.availableBytes(); + } + + @Override + public long skip(long n) throws IOException { + if (n <= 0) { + return 0; + } + long skipped = stream.skipBytes(n); + bytesRead += skipped; + return skipped; + } + + @Override + public long transferTo(OutputStream out) throws IOException { + Objects.requireNonNull(out, "out"); + byte[] scratch = null; + long transferred = 0; + while (true) { + // Block for the next chunk; writeNextChunkTo holds the internal lock only while + // dequeuing, then writes to `out` without any lock held. + int written = stream.writeNextChunkTo(out, scratch); + if (written == JavaHttpClientStreamingDataStream.SCRATCH_NEEDED) { + // Stream has a non-array-backed chunk ready; allocate a scratch buffer once + // and retry. The chunk stays at the head of the queue. + scratch = new byte[TRANSFER_SCRATCH_SIZE]; + continue; + } + if (written < 0) { + return transferred; + } + transferred += written; + bytesRead += written; + } + } + + @Override + public byte[] readAllBytes() throws IOException { + long contentLength = stream.contentLength(); + if (contentLength < 0) { + // Unknown length: fall back to the default growable path. + return super.readAllBytes(); + } + long remaining = contentLength - bytesRead; + if (remaining <= 0) { + return new byte[0]; + } + if (remaining > Integer.MAX_VALUE - 8) { + // Defensive: too large to allocate as a single array. + return super.readAllBytes(); + } + byte[] out = new byte[(int) remaining]; + int off = 0; + while (off < out.length) { + int n = stream.readInto(out, off, out.length - off); + if (n < 0) { + // Server closed early relative to the advertised content-length. Return what + // we got rather than a mostly-empty oversized array. + byte[] shorter = new byte[off]; + System.arraycopy(out, 0, shorter, 0, off); + bytesRead += off; + return shorter; + } + off += n; + } + bytesRead += out.length; + return out; + } + + @Override + public byte[] readNBytes(int len) throws IOException { + if (len < 0) { + throw new IllegalArgumentException("len < 0"); + } + if (len == 0) { + return new byte[0]; + } + long contentLength = stream.contentLength(); + // If content-length is known, we can cap the target at the remaining bytes and avoid + // the super implementation's growable ArrayList-of-chunks allocation. + if (contentLength >= 0) { + long remaining = contentLength - bytesRead; + if (remaining <= 0) { + return new byte[0]; + } + int target = (int) Math.min((long) len, remaining); + byte[] out = new byte[target]; + int off = 0; + while (off < out.length) { + int n = stream.readInto(out, off, out.length - off); + if (n < 0) { + break; + } + off += n; + } + if (off < out.length) { + byte[] shorter = new byte[off]; + System.arraycopy(out, 0, shorter, 0, off); + bytesRead += off; + return shorter; + } + bytesRead += off; + return out; + } + return super.readNBytes(len); + } + + @Override + public void close() { + stream.close(); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientTransport.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientTransport.java index dad5661833..294e6d5a5a 100644 --- a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientTransport.java +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpClientTransport.java @@ -41,11 +41,13 @@ */ public final class JavaHttpClientTransport implements ClientTransport { - private static final int SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD = 1024 * 256; // 256 KB + private static final String SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD_PROPERTY = + "software.amazon.smithy.java.client.http.smallResponseBodyFastPathThreshold"; + private static final int DEFAULT_SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD = 1024 * 64; // 64 KiB // Drop content-length private static final HeaderWithValueConsumer VALUE_CONSUMER = (b, n, v) -> { - if (n != HeaderName.CONTENT_LENGTH.name()) { + if (!HeaderName.CONTENT_LENGTH.name().equals(n)) { b.header(n, v); } }; @@ -54,6 +56,7 @@ public final class JavaHttpClientTransport implements ClientTransport responseBodyHandler; static { setHostProperties(); @@ -80,6 +83,7 @@ public JavaHttpClientTransport() { this.ownedExecutor = Executors.newVirtualThreadPerTaskExecutor(); this.client = HttpClient.newBuilder().executor(ownedExecutor).build(); this.defaultRequestTimeout = null; + this.responseBodyHandler = new ResponseBodyHandler(smallResponseBodyFastPathThreshold()); setHostProperties(); } @@ -91,6 +95,7 @@ public JavaHttpClientTransport(HttpClient client, Duration defaultRequestTimeout this.client = client; this.ownedExecutor = null; this.defaultRequestTimeout = defaultRequestTimeout; + this.responseBodyHandler = new ResponseBodyHandler(smallResponseBodyFastPathThreshold()); setHostProperties(); } @@ -98,6 +103,7 @@ private JavaHttpClientTransport(HttpClient client, ExecutorService ownedExecutor this.client = client; this.ownedExecutor = ownedExecutor; this.defaultRequestTimeout = defaultRequestTimeout; + this.responseBodyHandler = new ResponseBodyHandler(smallResponseBodyFastPathThreshold()); setHostProperties(); } @@ -130,6 +136,23 @@ private static boolean containsHost(String value) { return false; } + private static int smallResponseBodyFastPathThreshold() { + var value = System.getProperty(SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD_PROPERTY); + if (value == null) { + return DEFAULT_SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD; + } + try { + return Math.max(0, Integer.parseInt(value)); + } catch (NumberFormatException e) { + LOGGER.warn( + "Invalid {} value '{}'; using default {}", + SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD_PROPERTY, + value, + DEFAULT_SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD); + return DEFAULT_SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD; + } + } + @Override public MessageExchange messageExchange() { return HttpMessageExchange.INSTANCE; @@ -161,7 +184,7 @@ private java.net.http.HttpRequest createJavaRequest(Context context, HttpRequest private HttpResponse sendRequest(java.net.http.HttpRequest request) { java.net.http.HttpResponse res = null; try { - res = client.send(request, ResponseBodyHandler.INSTANCE); + res = client.send(request, responseBodyHandler); return createSmithyResponse(res); } catch (IOException | InterruptedException | RuntimeException e) { if (res != null) { @@ -255,11 +278,14 @@ public MessageExchange messageExchange() { * Picks a {@link BodySubscriber} implementation based on the advertised response size. * *

Small-body fast path ({@link ZeroCopyBodySubscriber}): when {@code Content-Length} is present and within - * {@link #SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD}. Otherwise, falls back to the JDK's built-in - * {@code ofInputStream()} body subscriber. + * the configured threshold. Otherwise, falls back to the JDK's built-in {@code ofInputStream()} body subscriber. */ private static final class ResponseBodyHandler implements BodyHandler { - static final ResponseBodyHandler INSTANCE = new ResponseBodyHandler(); + private final int smallResponseBodyFastPathThreshold; + + private ResponseBodyHandler(int smallResponseBodyFastPathThreshold) { + this.smallResponseBodyFastPathThreshold = smallResponseBodyFastPathThreshold; + } @Override public BodySubscriber apply(ResponseInfo responseInfo) { @@ -268,7 +294,7 @@ public BodySubscriber apply(ResponseInfo responseInfo) { if (contentLength == 0) { String contentType = responseInfo.headers().firstValue("content-type").orElse(null); return BodySubscribers.replacing(DataStream.ofBytes(new byte[0], contentType)); - } else if (contentLength >= 0 && contentLength <= SMALL_RESPONSE_BODY_FAST_PATH_THRESHOLD) { + } else if (contentLength > 0 && contentLength <= smallResponseBodyFastPathThreshold) { return new ZeroCopyBodySubscriber(responseInfo.headers(), contentLength); } diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpResponse.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpResponse.java new file mode 100644 index 0000000000..9a48150095 --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/JavaHttpResponse.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.api.ModifiableHttpResponse; +import software.amazon.smithy.java.io.datastream.DataStream; + +record JavaHttpResponse( + HttpVersion httpVersion, + int statusCode, + HttpHeaders headers, + DataStream body) implements HttpResponse { + + @Override + public HttpResponse toUnmodifiable() { + return this; + } + + @Override + public ModifiableHttpResponse toModifiable() { + return toModifiableCopy(); + } + + @Override + public ModifiableHttpResponse toModifiableCopy() { + return HttpResponse.create() + .setHttpVersion(httpVersion) + .setStatusCode(statusCode) + .setHeaders(headers.toModifiable()) + .setBody(body); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/plugins/UserAgentPlugin.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/plugins/UserAgentPlugin.java index e9262ed4fc..bb221c6ab1 100644 --- a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/plugins/UserAgentPlugin.java +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/plugins/UserAgentPlugin.java @@ -53,6 +53,12 @@ static final class UserAgentInterceptor implements ClientInterceptor { private static final String UA_VERSION = "2.1"; private static final String STATIC_SEGMENT; + // The User-Agent for the common request: no app-id and no per-call feature IDs. Equal to + // STATIC_SEGMENT with its single trailing space trimmed. Precomputed so those requests + // skip the StringBuilder + toString churn entirely (createUa profiled as a per-request + // byte[]/String allocator), reserving the builder path for requests that actually carry an + // app-id or feature IDs. + private static final String DEFAULT_UA; private static final String ENV_APP_ID = "AWS_SDK_UA_APP_ID"; private static final String SYSTEM_APP_ID = "aws.userAgentAppId"; @@ -73,6 +79,7 @@ static final class UserAgentInterceptor implements ClientInterceptor { + " os/" + getOsFamily() + "#" + sanitizeValue(System.getProperty("os.version")) + " lang/java#" + sanitizeValue(System.getProperty("java.version")) + ' '; + DEFAULT_UA = STATIC_SEGMENT.substring(0, STATIC_SEGMENT.length() - 1); } @Override @@ -90,14 +97,19 @@ public RequestT modifyBeforeTransmit(RequestHook hook } private static String createUa(Context context) { + var appId = resolveAppId(context); + var features = context.get(CallContext.FEATURE_IDS); + // Common case — neither app-id nor feature IDs — is a constant; skip the builder. + if (appId == null && (features == null || features.isEmpty())) { + return DEFAULT_UA; + } + StringBuilder b = new StringBuilder(STATIC_SEGMENT); - var appId = resolveAppId(context); if (appId != null) { b.append("app/").append(sanitizeValue(appId)).append(' '); } - var features = context.get(CallContext.FEATURE_IDS); if (features != null && !features.isEmpty()) { b.append("m/"); for (var feature : features) { diff --git a/client/client-http/src/test/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStreamTest.java b/client/client-http/src/test/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStreamTest.java new file mode 100644 index 0000000000..063e32dbc9 --- /dev/null +++ b/client/client-http/src/test/java/software/amazon/smithy/java/client/http/JavaHttpClientStreamingInputStreamTest.java @@ -0,0 +1,486 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import org.junit.jupiter.api.Test; + +/** + * Tests for the overridden {@link InputStream} fast paths on + * {@link JavaHttpClientStreamingInputStream} — {@code transferTo}, {@code readAllBytes}, + * {@code readNBytes}, {@code available}, and {@code skip} — plus the supporting helpers on + * {@link JavaHttpClientStreamingDataStream}. Tests drive the stream directly using + * synthetic subscriber callbacks ({@code enqueueBatch}/{@code complete}/{@code fail}) + * rather than going over the wire. + */ +class JavaHttpClientStreamingInputStreamTest { + + /** No-op subscription; tests don't rely on request(n)/cancel() semantics. */ + private static final Flow.Subscription NO_OP_SUBSCRIPTION = new Flow.Subscription() { + @Override + public void request(long n) {} + + @Override + public void cancel() {} + }; + + private static JavaHttpClientStreamingDataStream newStream(long contentLength) { + JavaHttpClientStreamingDataStream stream = new JavaHttpClientStreamingDataStream( + "application/octet-stream", + contentLength); + stream.setSubscription(NO_OP_SUBSCRIPTION); + return stream; + } + + private static byte[] bytesOfLength(int n) { + byte[] out = new byte[n]; + for (int i = 0; i < n; i++) { + out[i] = (byte) (i & 0xFF); + } + return out; + } + + /** Split {@code data} into consecutive chunks of the given sizes and enqueue each as its own batch. */ + private static void feedChunks(JavaHttpClientStreamingDataStream stream, byte[] data, int... chunkSizes) { + int offset = 0; + for (int size : chunkSizes) { + byte[] chunk = new byte[size]; + System.arraycopy(data, offset, chunk, 0, size); + stream.enqueueBatch(List.of(ByteBuffer.wrap(chunk))); + offset += size; + } + assertEquals(data.length, offset, "chunkSizes must sum to data.length"); + } + + // ---- transferTo ---- + + @Test + void transferToWritesAllBytesAcrossMultipleChunks() throws IOException { + byte[] payload = bytesOfLength(4096 + 1234); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 1024, 512, 2048, 512 + 1234); + stream.complete(); + + try (InputStream in = stream.asInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + long transferred = in.transferTo(out); + assertEquals(payload.length, transferred); + assertArrayEquals(payload, out.toByteArray()); + } + } + + @Test + void transferToReturnsZeroForEmptyStream() throws IOException { + JavaHttpClientStreamingDataStream stream = newStream(0); + stream.complete(); + + try (InputStream in = stream.asInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + assertEquals(0L, in.transferTo(out)); + assertEquals(0, out.size()); + } + } + + @Test + void transferToWorksWithReadOnlyChunksLargerThanScratch() throws IOException { + // Force the non-array-backed (read-only view) path by wrapping an already-read-only buffer + // in an even more restrictive view. `ByteBuffer.wrap(...).asReadOnlyBuffer()` returns + // something whose hasArray() is false, which is exactly what the JDK subscriber delivers. + byte[] payload = bytesOfLength(64 * 1024 + 7); // larger than TRANSFER_SCRATCH_SIZE (16 KiB) + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + // enqueueBatch wraps each buffer in asReadOnlyBuffer(), so we hit the scratch path. + stream.enqueueBatch(List.of(ByteBuffer.wrap(payload))); + stream.complete(); + + try (InputStream in = stream.asInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + long transferred = in.transferTo(out); + assertEquals(payload.length, transferred); + assertArrayEquals(payload, out.toByteArray()); + } + } + + @Test + void transferToPropagatesOutputStreamIOException() { + JavaHttpClientStreamingDataStream stream = newStream(10); + feedChunks(stream, bytesOfLength(10), 10); + stream.complete(); + + InputStream in = stream.asInputStream(); + OutputStream failing = new OutputStream() { + @Override + public void write(int b) throws IOException { + throw new IOException("boom"); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + throw new IOException("boom"); + } + }; + IOException e = assertThrows(IOException.class, () -> in.transferTo(failing)); + assertEquals("boom", e.getMessage()); + } + + @Test + void transferToDoesNotHoldLockDuringSlowWrites() throws Exception { + // Verify that a slow consumer does not prevent the producer from enqueuing more data. + // If transferTo held the internal lock while writing to `out`, enqueueBatch would block + // until writeNextChunkTo finished; we assert that the producer thread completes while + // the consumer is still inside its (slow) write call. + byte[] chunk1 = bytesOfLength(512); + byte[] chunk2 = bytesOfLength(512); + JavaHttpClientStreamingDataStream stream = newStream(chunk1.length + chunk2.length); + stream.enqueueBatch(List.of(ByteBuffer.wrap(chunk1))); + + CountDownLatch consumerInsideWrite = new CountDownLatch(1); + CountDownLatch producerDone = new CountDownLatch(1); + AtomicLong consumerWroteBytes = new AtomicLong(); + + InputStream in = stream.asInputStream(); + OutputStream slow = new OutputStream() { + @Override + public void write(int b) throws IOException { + write(new byte[] {(byte) b}, 0, 1); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + consumerInsideWrite.countDown(); + // Stall until the producer confirms it finished enqueuing more data. + try { + assertTrue(producerDone.await(5, TimeUnit.SECONDS), "producer should not be blocked"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException(e); + } + consumerWroteBytes.addAndGet(len); + } + }; + + Thread consumer = new Thread(() -> { + try { + in.transferTo(slow); + } catch (IOException e) { + throw new AssertionError(e); + } + }, "consumer"); + consumer.start(); + + assertTrue(consumerInsideWrite.await(5, TimeUnit.SECONDS), "consumer should reach slow write"); + + // Now push another chunk and complete. If the consumer held the stream lock, these would + // block until the slow write returned; the latch below would never fire in time. + stream.enqueueBatch(List.of(ByteBuffer.wrap(chunk2))); + stream.complete(); + producerDone.countDown(); + + consumer.join(5_000); + assertFalse(consumer.isAlive(), "consumer should finish"); + assertThat(consumerWroteBytes.get(), greaterThanOrEqualTo((long) chunk1.length)); + } + + // ---- readAllBytes ---- + + @Test + void readAllBytesWithKnownContentLengthReturnsExactArray() throws IOException { + byte[] payload = bytesOfLength(8192); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 1000, 3000, 4192); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertArrayEquals(payload, in.readAllBytes()); + } + } + + @Test + void readAllBytesWithUnknownContentLengthFallsBackToDefault() throws IOException { + byte[] payload = bytesOfLength(5000); + JavaHttpClientStreamingDataStream stream = newStream(-1L); + feedChunks(stream, payload, 2500, 2500); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertArrayEquals(payload, in.readAllBytes()); + } + } + + @Test + void readAllBytesAfterPartialReadReturnsRemainder() throws IOException { + byte[] payload = bytesOfLength(1024); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 256, 768); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + byte[] first = new byte[200]; + int n = in.read(first); + assertEquals(200, n); + + byte[] rest = in.readAllBytes(); + assertEquals(payload.length - 200, rest.length); + byte[] combined = new byte[payload.length]; + System.arraycopy(first, 0, combined, 0, 200); + System.arraycopy(rest, 0, combined, 200, rest.length); + assertArrayEquals(payload, combined); + } + } + + @Test + void readAllBytesShortCircuitsWhenAlreadyAtAdvertisedLength() throws IOException { + byte[] payload = bytesOfLength(16); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 16); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertArrayEquals(payload, in.readAllBytes()); + // Next call sees zero remaining against the known length → empty array, no blocking. + assertArrayEquals(new byte[0], in.readAllBytes()); + } + } + + @Test + void readAllBytesReturnsShortArrayWhenServerClosesEarly() throws IOException { + // Advertise 1000 bytes, deliver only 400, then end the stream. + JavaHttpClientStreamingDataStream stream = newStream(1000); + stream.enqueueBatch(List.of(ByteBuffer.wrap(bytesOfLength(400)))); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + byte[] result = in.readAllBytes(); + assertEquals(400, result.length); + assertArrayEquals(bytesOfLength(400), result); + } + } + + // ---- readNBytes ---- + + @Test + void readNBytesReturnsExactlyRequestedWhenAvailable() throws IOException { + byte[] payload = bytesOfLength(4096); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 1024, 1024, 2048); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + byte[] head = in.readNBytes(1500); + assertEquals(1500, head.length); + byte[] expected = new byte[1500]; + System.arraycopy(payload, 0, expected, 0, 1500); + assertArrayEquals(expected, head); + } + } + + @Test + void readNBytesCapsAtContentLengthWithoutBlocking() throws IOException { + byte[] payload = bytesOfLength(100); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 100); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + // Request more than the advertised length; implementation should cap at contentLength + // and return a 100-byte array rather than block waiting for bytes that will never come. + byte[] result = in.readNBytes(10_000); + assertEquals(100, result.length); + assertArrayEquals(payload, result); + } + } + + @Test + void readNBytesWithZeroReturnsEmpty() throws IOException { + JavaHttpClientStreamingDataStream stream = newStream(10); + feedChunks(stream, bytesOfLength(10), 10); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertArrayEquals(new byte[0], in.readNBytes(0)); + } + } + + @Test + void readNBytesRejectsNegativeLength() { + JavaHttpClientStreamingDataStream stream = newStream(0); + stream.complete(); + try (InputStream in = stream.asInputStream()) { + assertThrows(IllegalArgumentException.class, () -> in.readNBytes(-1)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + // ---- available ---- + + @Test + void availableReflectsQueuedBytesBeforeAndAfterReads() throws IOException { + JavaHttpClientStreamingDataStream stream = newStream(-1L); + stream.enqueueBatch(List.of(ByteBuffer.wrap(bytesOfLength(100)), ByteBuffer.wrap(bytesOfLength(50)))); + + try (InputStream in = stream.asInputStream()) { + assertEquals(150, in.available()); + byte[] scratch = new byte[80]; + int n = in.read(scratch); + assertEquals(80, n); + assertEquals(70, in.available()); + } + } + + @Test + void availableReturnsZeroForEmptyCompletedStream() throws IOException { + JavaHttpClientStreamingDataStream stream = newStream(0); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertEquals(0, in.available()); + } + } + + // ---- skip ---- + + @Test + void skipAdvancesPositionWithoutReturningBytes() throws IOException { + byte[] payload = bytesOfLength(1000); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 400, 600); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + long skipped = in.skip(250); + assertEquals(250L, skipped); + byte[] rest = in.readAllBytes(); + assertEquals(750, rest.length); + byte[] expected = new byte[750]; + System.arraycopy(payload, 250, expected, 0, 750); + assertArrayEquals(expected, rest); + } + } + + @Test + void skipSpansMultipleChunks() throws IOException { + byte[] payload = bytesOfLength(3000); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 500, 500, 500, 500, 500, 500); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + long skipped = in.skip(1250); + assertEquals(1250L, skipped); + byte[] rest = in.readAllBytes(); + assertEquals(payload.length - 1250, rest.length); + byte[] expected = new byte[rest.length]; + System.arraycopy(payload, 1250, expected, 0, rest.length); + assertArrayEquals(expected, rest); + } + } + + @Test + void skipReturnsZeroAtEndOfStream() throws IOException { + byte[] payload = bytesOfLength(10); + JavaHttpClientStreamingDataStream stream = newStream(payload.length); + feedChunks(stream, payload, 10); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertEquals(10L, in.skip(10)); + assertEquals(0L, in.skip(100)); + } + } + + @Test + void skipOfZeroOrNegativeReturnsZero() throws IOException { + JavaHttpClientStreamingDataStream stream = newStream(10); + feedChunks(stream, bytesOfLength(10), 10); + stream.complete(); + + try (InputStream in = stream.asInputStream()) { + assertEquals(0L, in.skip(0)); + assertEquals(0L, in.skip(-5)); + } + } + + // ---- error propagation ---- + + @Test + void transferToPropagatesStreamFailure() { + JavaHttpClientStreamingDataStream stream = newStream(-1L); + RuntimeException cause = new RuntimeException("upstream broke"); + stream.fail(cause); + + InputStream in = stream.asInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + IOException e = assertThrows(IOException.class, () -> in.transferTo(out)); + assertEquals(cause, e.getCause()); + } + + @Test + void readAllBytesPropagatesStreamFailure() { + JavaHttpClientStreamingDataStream stream = newStream(500); + // Deliver some data, then fail mid-stream. + stream.enqueueBatch(List.of(ByteBuffer.wrap(bytesOfLength(100)))); + RuntimeException cause = new RuntimeException("upstream broke"); + stream.fail(cause); + + InputStream in = stream.asInputStream(); + IOException e = assertThrows(IOException.class, in::readAllBytes); + assertEquals(cause, e.getCause()); + } + + // ---- cross-thread integration ---- + + @Test + void transferToBlocksUntilProducerCompletes() throws Exception { + byte[] part1 = bytesOfLength(1024); + byte[] part2 = bytesOfLength(2048); + JavaHttpClientStreamingDataStream stream = newStream(part1.length + part2.length); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + AtomicBoolean done = new AtomicBoolean(); + InputStream in = stream.asInputStream(); + Thread consumer = new Thread(() -> { + try { + in.transferTo(out); + done.set(true); + } catch (IOException e) { + throw new AssertionError(e); + } + }, "consumer"); + consumer.start(); + + // Producer feeds in two pieces and then completes. + stream.enqueueBatch(List.of(ByteBuffer.wrap(part1))); + Thread.sleep(50); // let consumer drain + stream.enqueueBatch(List.of(ByteBuffer.wrap(part2))); + stream.complete(); + + consumer.join(5_000); + assertTrue(done.get(), "consumer should have finished"); + + byte[] expected = new byte[part1.length + part2.length]; + System.arraycopy(part1, 0, expected, 0, part1.length); + System.arraycopy(part2, 0, expected, part1.length, part2.length); + assertArrayEquals(expected, out.toByteArray()); + } +} diff --git a/client/client-rpcv2/src/main/java/software/amazon/smithy/java/client/rpcv2/AbstractRpcV2ClientProtocol.java b/client/client-rpcv2/src/main/java/software/amazon/smithy/java/client/rpcv2/AbstractRpcV2ClientProtocol.java index 0cc20ee5f9..4bb7cec7e7 100644 --- a/client/client-rpcv2/src/main/java/software/amazon/smithy/java/client/rpcv2/AbstractRpcV2ClientProtocol.java +++ b/client/client-rpcv2/src/main/java/software/amazon/smithy/java/client/rpcv2/AbstractRpcV2ClientProtocol.java @@ -108,7 +108,7 @@ public HttpRequest SmithyUri endpoint ) { var target = targetPathPrefix + operation.schema().id().getName(); - var builder = templateRequest.toModifiableCopy(); + ModifiableHttpRequest builder = templateRequest.toModifiableCopy(); builder.setUri(endpoint.withConcatPath(target)); if (operation.inputSchema().hasTrait(TraitKey.UNIT_TYPE_TRAIT)) { diff --git a/config/spotbugs/filter.xml b/config/spotbugs/filter.xml index 199ec4ee36..a01db75155 100644 --- a/config/spotbugs/filter.xml +++ b/config/spotbugs/filter.xml @@ -86,35 +86,40 @@ + - - + + + + - - + - - - - - + - - + + - - - + + - - - - + + @@ -153,4 +158,25 @@ + + + + + + + + + + + + + + + + + diff --git a/core/src/main/java/software/amazon/smithy/java/core/serde/event/DefaultEventStreamWriter.java b/core/src/main/java/software/amazon/smithy/java/core/serde/event/DefaultEventStreamWriter.java index 1dda096379..9f0e3254b1 100644 --- a/core/src/main/java/software/amazon/smithy/java/core/serde/event/DefaultEventStreamWriter.java +++ b/core/src/main/java/software/amazon/smithy/java/core/serde/event/DefaultEventStreamWriter.java @@ -5,6 +5,10 @@ package software.amazon.smithy.java.core.serde.event; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -31,16 +35,19 @@ final class DefaultEventStreamWriter> implements ProtocolEventStreamWriter { private static final InternalLogger LOGGER = InternalLogger.getLogger(DefaultEventStreamWriter.class); + /** * Default timeout to block waiting to write. */ private static final int WRITE_TIMEOUT_MILLIS = 10_000; + /** * This latch is used to ensure that the protocol handler writes the initial event * before any other event is written. Protocols that don't require the initial event still have * to unlatch the writer by bootstrapping it with a null value. */ private final CountDownLatch readyLatch = new CountDownLatch(1); + /** * Pipes bytes written by this writer to an input stream used * to send them over the wire. @@ -184,8 +191,7 @@ private void checkState() { @Override public EventStreamReader asReader() { - throw new UnsupportedOperationException( - "This writer cannot be converted to a reader"); + throw new UnsupportedOperationException("This writer cannot be converted to a reader"); } @Override @@ -233,6 +239,64 @@ public void close() { */ @Override public DataStream toDataStream() { - return DataStream.ofInputStream(pipeStream); + return new EventStreamDataStream(pipeStream); + } + + /** + * A {@link DataStream} over the event pipe whose {@link #writeTo(OutputStream)} flushes after each event + * (see {@link EventPipeStream#writeMessagesTo}), so a transport draining via {@code writeTo} emits one + * frame per event. Still works as an ordinary unknown-length, non-replayable {@code InputStream}-backed + * stream via {@link #asInputStream()}. + */ + private static final class EventStreamDataStream implements DataStream { + private final EventPipeStream pipeStream; + // The pipe is single-use: once drained (via writeTo/asInputStream) or closed it cannot be replayed. + private final AtomicBoolean consumed = new AtomicBoolean(false); + + EventStreamDataStream(EventPipeStream pipeStream) { + this.pipeStream = pipeStream; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + consumed.set(true); + pipeStream.writeMessagesTo(out); + } + + @Override + public InputStream asInputStream() { + consumed.set(true); + return pipeStream; + } + + @Override + public long contentLength() { + return -1; + } + + @Override + public String contentType() { + return null; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return !consumed.get(); + } + + @Override + public void close() { + consumed.set(true); + try { + pipeStream.close(); + } catch (IOException e) { + throw new UncheckedIOException("Failed to close event stream", e); + } + } } } diff --git a/core/src/main/java/software/amazon/smithy/java/core/serde/event/EventPipeStream.java b/core/src/main/java/software/amazon/smithy/java/core/serde/event/EventPipeStream.java index 49f6d9dcb3..769eaab8aa 100644 --- a/core/src/main/java/software/amazon/smithy/java/core/serde/event/EventPipeStream.java +++ b/core/src/main/java/software/amazon/smithy/java/core/serde/event/EventPipeStream.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; @@ -30,6 +31,7 @@ */ final class EventPipeStream extends InputStream { private static final InternalLogger LOGGER = InternalLogger.getLogger(EventPipeStream.class); + /** * Poison pill used to signal the end of the stream. */ @@ -160,6 +162,56 @@ public int read() throws IOException { return b & 0xFF; } + /** + * Drains queued event messages to {@code out}, writing each whole and flushing after it. This keeps + * per-event boundaries (unlike a byte-oriented {@code transferTo}), so a flushing transport sends each + * event as its own frame instead of buffering. Blocks the consumer thread until {@link #complete()} + * (returns) or {@link #completeWithError} (throws). + * + * @param out the sink to write messages to + * @throws IOException if writing fails, the producer signalled an error, or the thread is interrupted + */ + void writeMessagesTo(OutputStream out) throws IOException { + if (closed) { + throw new IOException("Stream is closed"); + } + + // Flush any buffer left partially consumed by a prior read() first. + if (current != null && current != POISON_PILL) { + writeBuffer(out, current); + current = null; + out.flush(); + } + + while (true) { + ByteBuffer message; + try { + message = queue.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while reading", e); + } + + if (message == POISON_PILL) { + checkError(); + return; + } + + writeBuffer(out, message); + out.flush(); + } + } + + private static void writeBuffer(OutputStream out, ByteBuffer message) throws IOException { + if (message.hasArray()) { + out.write(message.array(), message.arrayOffset() + message.position(), message.remaining()); + } else { + byte[] tmp = new byte[message.remaining()]; + message.get(tmp); + out.write(tmp); + } + } + @Override public int available() throws IOException { checkError(); diff --git a/core/src/test/java/software/amazon/smithy/java/core/serde/event/EventPipeStreamTest.java b/core/src/test/java/software/amazon/smithy/java/core/serde/event/EventPipeStreamTest.java index 84cd480d31..98b5e4e6b4 100644 --- a/core/src/test/java/software/amazon/smithy/java/core/serde/event/EventPipeStreamTest.java +++ b/core/src/test/java/software/amazon/smithy/java/core/serde/event/EventPipeStreamTest.java @@ -9,8 +9,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -83,4 +87,42 @@ static String[] sources() { static byte[] charToUtf8Bytes(char c) { return Character.toString(c).getBytes(StandardCharsets.UTF_8); } + + @Test + void writeMessagesToFlushesOncePerEvent() throws IOException { + var pipe = new EventPipeStream(); + var events = new String[] {"syn", "event-two", "fin"}; + Thread.ofVirtual().start(() -> { + for (var e : events) { + pipe.write(ByteBuffer.wrap(e.getBytes(StandardCharsets.UTF_8))); + } + pipe.complete(); + }); + + // Records the bytes accumulated at each flush() so we can assert one flush == one whole event. + var flushes = new ArrayList(); + var current = new ByteArrayOutputStream(); + var recordingSink = new OutputStream() { + @Override + public void write(int b) { + current.write(b); + } + + @Override + public void write(byte[] b, int off, int len) { + current.write(b, off, len); + } + + @Override + public void flush() { + flushes.add(current.toString(StandardCharsets.UTF_8)); + current.reset(); + } + }; + + pipe.writeMessagesTo(recordingSink); + + // One flush per event, in order, proving boundaries are preserved (transferTo would coalesce them). + assertEquals(List.of("syn", "event-two", "fin"), flushes); + } } diff --git a/examples/basic-server/build.gradle.kts b/examples/basic-server/build.gradle.kts index 7d388c6efe..2aa70b616d 100644 --- a/examples/basic-server/build.gradle.kts +++ b/examples/basic-server/build.gradle.kts @@ -3,6 +3,12 @@ plugins { application } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + dependencies { val smithyJavaVersion: String by project diff --git a/examples/end-to-end/build.gradle.kts b/examples/end-to-end/build.gradle.kts index c5fee0a6dd..df32a1d8b3 100644 --- a/examples/end-to-end/build.gradle.kts +++ b/examples/end-to-end/build.gradle.kts @@ -3,6 +3,12 @@ plugins { application } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + application { mainClass = "software.amazon.smithy.java.server.example.BasicServerExample" } diff --git a/examples/event-streaming-client/build.gradle.kts b/examples/event-streaming-client/build.gradle.kts index a925064fb8..871207e1c4 100644 --- a/examples/event-streaming-client/build.gradle.kts +++ b/examples/event-streaming-client/build.gradle.kts @@ -3,6 +3,12 @@ plugins { id("software.amazon.smithy.java.gradle.smithy-java") } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + dependencies { val smithyJavaVersion: String by project diff --git a/examples/mcp-traits-example/build.gradle.kts b/examples/mcp-traits-example/build.gradle.kts index 742febb904..d703ab948f 100644 --- a/examples/mcp-traits-example/build.gradle.kts +++ b/examples/mcp-traits-example/build.gradle.kts @@ -3,6 +3,12 @@ plugins { id("software.amazon.smithy.gradle.smithy-base") } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + dependencies { val smithyJavaVersion: String by project val smithyVersion: String by project diff --git a/examples/restjson-client/build.gradle.kts b/examples/restjson-client/build.gradle.kts index 650279e67f..6a713b7b1f 100644 --- a/examples/restjson-client/build.gradle.kts +++ b/examples/restjson-client/build.gradle.kts @@ -5,6 +5,12 @@ plugins { id("me.champeau.jmh") } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + dependencies { val smithyJavaVersion: String by project diff --git a/examples/standalone-types/build.gradle.kts b/examples/standalone-types/build.gradle.kts index 931f5bd6ac..2e689a3532 100644 --- a/examples/standalone-types/build.gradle.kts +++ b/examples/standalone-types/build.gradle.kts @@ -3,6 +3,12 @@ plugins { id("software.amazon.smithy.java.gradle.smithy-java") } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + dependencies { testImplementation("org.hamcrest:hamcrest:3.0") testImplementation("org.junit.jupiter:junit-jupiter:6.1.0") diff --git a/http/http-api/src/main/java/software/amazon/smithy/java/http/api/TrailerSupport.java b/http/http-api/src/main/java/software/amazon/smithy/java/http/api/TrailerSupport.java new file mode 100644 index 0000000000..943bf69527 --- /dev/null +++ b/http/http-api/src/main/java/software/amazon/smithy/java/http/api/TrailerSupport.java @@ -0,0 +1,37 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.api; + +/** + * Marker interface for HTTP message bodies that support trailer headers. + * + *

Response bodies from HTTP/2 or chunked HTTP/1.1 transfers may carry + * trailing headers after the body data. Call {@link #trailerHeaders()} after + * the body is fully read to access them. + * + *

Request bodies can implement this interface to provide trailing headers + * that are sent after the request body is fully written (e.g., streaming checksums). + * + *

Usage: + * {@snippet : + * var response = client.send(request); + * response.body().asInputStream().readAllBytes(); + * if (response.body() instanceof TrailerSupport ts) { + * HttpHeaders trailers = ts.trailerHeaders(); + * } + * } + */ +public interface TrailerSupport { + /** + * Get trailer headers. + * + *

For response bodies, this blocks until the body is fully read and trailers + * are available. For request bodies, this is evaluated after the body is fully written. + * + * @return trailer headers, or empty headers if none present + */ + HttpHeaders trailerHeaders(); +} diff --git a/http/http-binding/src/main/java/software/amazon/smithy/java/http/binding/ResponseDeserializer.java b/http/http-binding/src/main/java/software/amazon/smithy/java/http/binding/ResponseDeserializer.java index c599af0046..5f7a2772eb 100644 --- a/http/http-binding/src/main/java/software/amazon/smithy/java/http/binding/ResponseDeserializer.java +++ b/http/http-binding/src/main/java/software/amazon/smithy/java/http/binding/ResponseDeserializer.java @@ -5,8 +5,12 @@ package software.amazon.smithy.java.http.binding; +import java.io.IOException; +import java.io.UncheckedIOException; import software.amazon.smithy.java.core.error.ModeledException; +import software.amazon.smithy.java.core.schema.Schema; import software.amazon.smithy.java.core.schema.ShapeBuilder; +import software.amazon.smithy.java.core.schema.TraitKey; import software.amazon.smithy.java.core.serde.Codec; import software.amazon.smithy.java.core.serde.event.EventDecoderFactory; import software.amazon.smithy.java.core.serde.event.Frame; @@ -21,6 +25,7 @@ public final class ResponseDeserializer { private final HttpBindingDeserializer.Builder deserBuilder = HttpBindingDeserializer.builder(); private ShapeBuilder outputShapeBuilder; private ShapeBuilder errorShapeBuilder; + private DataStream responseBody; ResponseDeserializer() {} @@ -58,6 +63,7 @@ public ResponseDeserializer payloadMediaType(String payloadMediaType) { */ public ResponseDeserializer response(HttpResponse response) { DataStream bodyDataStream = bodyDataStream(response); + responseBody = bodyDataStream; deserBuilder.headers(response.headers()) .responseStatus(response.statusCode()) .body(bodyDataStream); @@ -117,6 +123,39 @@ public void deserialize() { HttpBindingDeserializer deserializer = deserBuilder.build(); var target = outputShapeBuilder != null ? outputShapeBuilder : errorShapeBuilder; - target.deserialize(deserializer); + Throwable failure = null; + try { + target.deserialize(deserializer); + } catch (Throwable t) { + failure = t; + throw t; + } finally { + if (!hasStreamingPayload(target.schema())) { + discardResponseBody(failure); + } + } + } + + private static boolean hasStreamingPayload(Schema schema) { + var ext = schema.getExtension(HttpBindingSchemaExtensions.KEY); + if (ext instanceof HttpBindingSchemaExtensions.StructBindings sb) { + var payloadMember = sb.response().payloadMember; + return payloadMember != null && payloadMember.hasTrait(TraitKey.STREAMING_TRAIT); + } + return false; + } + + private void discardResponseBody(Throwable failure) { + if (responseBody != null) { + try { + responseBody.discard(); + } catch (IOException e) { + var wrapped = new UncheckedIOException(e); + if (failure == null) { + throw wrapped; + } + failure.addSuppressed(wrapped); + } + } } } diff --git a/http/http-binding/src/test/java/software/amazon/smithy/java/http/binding/HttpBindingDeserializerTest.java b/http/http-binding/src/test/java/software/amazon/smithy/java/http/binding/HttpBindingDeserializerTest.java index 2d54bfe7c0..ac30699e41 100644 --- a/http/http-binding/src/test/java/software/amazon/smithy/java/http/binding/HttpBindingDeserializerTest.java +++ b/http/http-binding/src/test/java/software/amazon/smithy/java/http/binding/HttpBindingDeserializerTest.java @@ -5,13 +5,43 @@ package software.amazon.smithy.java.http.binding; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; import java.util.List; +import java.util.Map; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +import software.amazon.smithy.java.core.schema.ShapeBuilder; +import software.amazon.smithy.java.core.serde.Codec; +import software.amazon.smithy.java.core.serde.ShapeDeserializer; +import software.amazon.smithy.java.core.serde.ShapeSerializer; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.HttpPayloadTrait; +import software.amazon.smithy.model.traits.StreamingTrait; public class HttpBindingDeserializerTest { + private static final Codec NOOP_CODEC = new Codec() { + @Override + public ShapeSerializer createSerializer(OutputStream sink) { + throw new UnsupportedOperationException(); + } + + @Override + public ShapeDeserializer createDeserializer(ByteBuffer source) { + throw new UnsupportedOperationException(); + } + }; @ParameterizedTest @MethodSource("contentTypeMatchProvider") @@ -48,4 +78,154 @@ static List contentTypeMatchProvider() { Arguments.of("application/json", null, 1) // No expectation ); } + + @Test + void responseDeserializerDiscardsBodyForNonStreamingOutput() { + var body = new TrackingDataStream(); + + new ResponseDeserializer() + .payloadCodec(NOOP_CODEC) + .response(response(body)) + .outputShapeBuilder(new NonStreamingOutput.Builder()) + .deserialize(); + + Assertions.assertEquals(1, body.discardCount); + } + + @Test + void responseDeserializerLeavesStreamingPayloadOpen() { + var body = new TrackingDataStream(); + var builder = new StreamingOutput.Builder(); + + new ResponseDeserializer() + .payloadCodec(NOOP_CODEC) + .response(response(body)) + .outputShapeBuilder(builder) + .deserialize(); + + Assertions.assertSame(body, builder.body); + Assertions.assertEquals(0, body.discardCount); + } + + private static HttpResponse response(DataStream body) { + return HttpResponse.of(HttpVersion.HTTP_1_1, 200, HttpHeaders.of(Map.of()), body); + } + + private static final class TrackingDataStream implements DataStream { + int discardCount; + + @Override + public long contentLength() { + return -1; + } + + @Override + public String contentType() { + return null; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public InputStream asInputStream() { + return new ByteArrayInputStream(new byte[0]); + } + + @Override + public void discard() { + discardCount++; + } + } + + private record NonStreamingOutput() implements SerializableStruct { + static final Schema SCHEMA = Schema.structureBuilder(ShapeId.from("smithy.example#NonStreamingOutput")) + .builderSupplier(Builder::new) + .build(); + + @Override + public Schema schema() { + return SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) {} + + @Override + public T getMemberValue(Schema member) { + return null; + } + + private static final class Builder implements ShapeBuilder { + @Override + public NonStreamingOutput build() { + return new NonStreamingOutput(); + } + + @Override + public ShapeBuilder deserialize(ShapeDeserializer decoder) { + decoder.readStruct(SCHEMA, this, (builder, member, deserializer) -> {}); + return this; + } + + @Override + public Schema schema() { + return SCHEMA; + } + } + } + + private record StreamingOutput(DataStream body) implements SerializableStruct { + private static final Schema STREAMING_BLOB = Schema.createBlob( + ShapeId.from("smithy.example#StreamingBlob"), + new StreamingTrait()); + static final Schema SCHEMA = Schema.structureBuilder(ShapeId.from("smithy.example#StreamingOutput")) + .putMember("body", STREAMING_BLOB, new HttpPayloadTrait()) + .builderSupplier(Builder::new) + .build(); + + @Override + public Schema schema() { + return SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) {} + + @Override + public T getMemberValue(Schema member) { + return null; + } + + private static final class Builder implements ShapeBuilder { + private DataStream body; + + @Override + public StreamingOutput build() { + return new StreamingOutput(body); + } + + @Override + public ShapeBuilder deserialize(ShapeDeserializer decoder) { + decoder.readStruct(SCHEMA, this, (builder, member, deserializer) -> { + if (member.memberName().equals("body")) { + builder.body = deserializer.readDataStream(member); + } + }); + return this; + } + + @Override + public Schema schema() { + return SCHEMA; + } + } + } } diff --git a/http/http-client/build.gradle.kts b/http/http-client/build.gradle.kts index 98b1f1b175..5a1496128b 100644 --- a/http/http-client/build.gradle.kts +++ b/http/http-client/build.gradle.kts @@ -1,15 +1,17 @@ import java.net.Socket +import java.util.Properties plugins { - java + id("smithy-java.module-conventions") id("smithy-java.jmh-conventions") } -repositories { - mavenLocal() - mavenCentral() -} +description = "Smithy's generic blocking HTTP client with bidirectional streaming" + +extra["displayName"] = "Smithy :: Java :: HTTP :: Client" +extra["moduleName"] = "software.amazon.smithy.java.http.client" +// Separate source set for benchmark server (runs in separate process for clean flame graphs) sourceSets { create("jmhServer") { java.srcDir("src/jmhServer/java") @@ -19,16 +21,63 @@ sourceSets { val jmhServerImplementation by configurations.getting dependencies { + api(project(":http:http-api")) + api(project(":logging")) + + // netty-common provides HashedWheelTimer: a single shared timer wheel backs the per-read + // deadline watchdog in SSLEngineTransport (arm/cancel is O(1), no per-read epoll Selector). + implementation("io.netty:netty-common:4.2.13.Final") + + // Experimental persistent-registration epoll socket backend (opt-in, Linux-only). Provides the + // io.netty.channel.unix.Socket / io.netty.channel.epoll.{Native,EpollEventArray,Epoll} types the + // EpollChannel/EpollReactor/EpollAccess classes use. The classes (compile) are cross-platform; the + // native .so is pulled per-arch at runtime only and gated behind Epoll.isAvailable() so non-Linux + // hosts (and the default NIO path) never load it. + implementation("io.netty:netty-transport-native-epoll:4.2.13.Final") + runtimeOnly("io.netty:netty-transport-native-epoll:4.2.13.Final:linux-x86_64") + runtimeOnly("io.netty:netty-transport-native-epoll:4.2.13.Final:linux-aarch_64") + + // Netty for HTTP/2 integration tests + testImplementation("io.netty:netty-all:4.2.7.Final") + testImplementation("org.bouncycastle:bcpkix-jdk18on:1.78.1") + // Jackson for HPACK test suite JSON parsing + testImplementation("com.fasterxml.jackson.core:jackson-databind:2.18.2") + + // Jazzer for fuzz testing + testImplementation(libs.jazzer.junit) + testImplementation(libs.jazzer.api) + + // Add Apache HttpClient for benchmarking comparison + jmh("org.apache.httpcomponents.client5:httpclient5:5.5") + + // Helidon WebClient for benchmarking comparison + jmh("io.helidon.webclient:helidon-webclient:4.1.6") + jmh("io.helidon.webclient:helidon-webclient-http2:4.1.6") + + // Netty for raw HTTP/2 benchmarking + jmh("io.netty:netty-all:4.2.7.Final") + + // Productionized smithy transports for benchmarking jmh(project(":client:client-http")) + jmh(project(":client:client-http-boringssl")) + jmh(project(":client:client-core")) - jmhServerImplementation("io.netty:netty-all:4.2.15.Final") - jmhServerImplementation("org.bouncycastle:bcpkix-jdk18on:1.84") + // Benchmark server dependencies (Netty runs in separate process) + jmhServerImplementation("io.netty:netty-all:4.2.7.Final") + jmhServerImplementation("org.bouncycastle:bcpkix-jdk18on:1.78.1") } +// Fixed ports for benchmark server (matches BenchmarkServer.java defaults) +val benchmarkH1Port = 18080 +val benchmarkH2Port = 18443 val benchmarkH2cPort = 18081 + val benchmarkPidFile = layout.buildDirectory.file("benchmark-server.pid") + +// Capture classpath at configuration time for config cache compatibility val jmhServerClasspath = sourceSets["jmhServer"].runtimeClasspath +// Task to start the benchmark server in a background process val startBenchmarkServer by tasks.registering { dependsOn("jmhServerClasses") notCompatibleWithConfigurationCache("Starts external process") @@ -37,16 +86,24 @@ val startBenchmarkServer by tasks.registering { val pidFile = benchmarkPidFile.get().asFile pidFile.parentFile.mkdirs() - val process = + // Build classpath for server + val serverClasspath = jmhServerClasspath.asPath + + val processBuilder = ProcessBuilder( "java", "-cp", - jmhServerClasspath.asPath, + serverClasspath, "software.amazon.smithy.java.http.client.BenchmarkServer", - ).inheritIO().start() + ) + processBuilder.inheritIO() + val process = processBuilder.start() + + // Store PID for later cleanup pidFile.writeText(process.pid().toString()) + // Wait for server to be ready (try connecting) var attempts = 0 var ready = false while (!ready && attempts < 50) { @@ -59,8 +116,8 @@ val startBenchmarkServer by tasks.registering { try { Socket("localhost", benchmarkH2cPort).close() ready = true - } catch (_: Exception) { - // Server not ready yet. + } catch (e: Exception) { + // Server not ready yet } } @@ -68,9 +125,20 @@ val startBenchmarkServer by tasks.registering { process.destroyForcibly() throw GradleException("Benchmark server failed to start (not ready after 5s)") } + + if (!process.isAlive) { + pidFile.delete() + throw GradleException("Benchmark server exited during startup") + } + + println("Benchmark server started (PID: ${process.pid()})") + println(" H1: http://localhost:$benchmarkH1Port") + println(" H2: https://localhost:$benchmarkH2Port") + println(" H2C: http://localhost:$benchmarkH2cPort") } } +// Task to stop the benchmark server val stopBenchmarkServer by tasks.registering { notCompatibleWithConfigurationCache("Stops external process") @@ -79,31 +147,92 @@ val stopBenchmarkServer by tasks.registering { if (pidFile.exists()) { val pid = pidFile.readText().trim().toLong() try { - ProcessHandle.of(pid).ifPresent { handle -> handle.destroy() } - } catch (_: Exception) { - // Best effort cleanup. + ProcessHandle.of(pid).ifPresent { handle -> + handle.destroy() + println("Stopped benchmark server (PID: $pid)") + } + } catch (e: Exception) { + println("Warning: Could not stop server: ${e.message}") } pidFile.delete() } } } +// External benchmark-server host. When non-null: +// * the local startBenchmarkServer/stopBenchmarkServer hooks are skipped (you start the +// server yourself on the remote host) +// * -Djmh.bench.host=$externalBenchHost is forwarded into the forked JMH JVM so +// BenchmarkSupport.BENCH_HOST resolves to the remote host +// Set via -Pjmh.bench.host= or the BENCH_HOST env var. +val externalBenchHost = + (project.findProperty("jmh.bench.host") as String?)?.takeIf { it.isNotBlank() } + ?: System.getenv("BENCH_HOST")?.takeIf { it.isNotBlank() } + +// Configure JMH +// Run with: ./gradlew :http:http-client:jmh -Pjmh.includes="H2cScalingBenchmark.smithy" +// To customize params, edit @Param annotations in benchmark source files jmh { - iterations = 3 - includes.set( - providers.gradleProperty("jmh.includes") - .map { listOf(it) } - .orElse(listOf(".*")), - ) + val includesProp = project.findProperty("jmh.includes")?.toString() + val jvmArgsProp = project.findProperty("jmh.jvmArgsAppend")?.toString() + val profilersProp = project.findProperty("jmh.profilers")?.toString() + includes = if (includesProp != null) listOf(includesProp) else listOf(".*") + + warmupIterations = (project.findProperty("jmh.warmupIterations") as String?)?.toInt() ?: 3 + iterations = (project.findProperty("jmh.iterations") as String?)?.toInt() ?: 3 + fork = (project.findProperty("jmh.fork") as String?)?.toInt() ?: 1 resultFormat = "CSV" resultsFile = project.file("build/reports/jmh/results.csv") - jvmArgsAppend.addAll("-Djdk.httpclient.allowRestrictedHeaders=host") - providers.gradleProperty("jmh.jvmArgsAppend").orNull?.let { args -> - jvmArgsAppend.addAll(args.split(Regex("\\s*;\\s*")).filter { it.isNotEmpty() }) + val args = mutableListOf() + if (jvmArgsProp != null) { + args += jvmArgsProp.split(Regex("\\s*;\\s*")).filter { it.isNotEmpty() } + } + // Forward -Pjmh.bench.host into the forked JMH JVM so BenchmarkSupport sees it. + if (externalBenchHost != null) { + args += "-Djmh.bench.host=$externalBenchHost" + } + if (args.isNotEmpty()) { + jvmArgsAppend = args + } + if (profilersProp != null) { + val profilerSpecs = + if (profilersProp.contains(";;")) { + profilersProp.split(Regex("\\s*;;\\s*")).filter { it.isNotEmpty() } + } else { + listOf(profilersProp) + } + profilers.addAll(profilerSpecs) } + // Use standalone asprof for profiling instead of bundled async profiler + // profilers.add("async:output=flamegraph") + // profilers.add("gc") + + // JIT diagnostics - uncomment for trace-abort analysis + // jvmArgsAppend = listOf( + // "-XX:+UnlockDiagnosticVMOptions", + // "-XX:+LogCompilation", + // "-XX:LogFile=build/reports/jmh/jit.log", + // "-XX:+TraceDeoptimization", + // "-XX:+PrintInlining" + // ) + + // Attach async-profiler via agentpath for profiling + // val apLib = ... + // jvmArgsAppend = listOf(...) } +// Make jmh task auto-start/stop the benchmark server, unless an external host is targeted +// via -Pjmh.bench.host= (or the BENCH_HOST env var). When an external host is used, +// start the server yourself on that host (java -jar build/libs/.../jmhServer.jar etc.). tasks.named("jmh") { - dependsOn(startBenchmarkServer) - finalizedBy(stopBenchmarkServer) + if (externalBenchHost == null) { + dependsOn(startBenchmarkServer) + finalizedBy(stopBenchmarkServer) + } + // Note: when targeting an external host (-Pjmh.bench.host=...), start the BenchmarkServer + // yourself on that host — the local start/stop hooks are skipped here. +} + +tasks.test { + maxHeapSize = "2g" } diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestResponseTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestResponseTest.java new file mode 100644 index 0000000000..070c65de37 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestResponseTest.java @@ -0,0 +1,205 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SSLContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.TestCertificateGenerator; +import software.amazon.smithy.java.http.client.it.server.h1.MultiplexingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.RequestCapturingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.MultiplexingHttp2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.RequestCapturingHttp2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.TextResponseHttp2ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Parameterized test for basic request/response across all transport configurations. + */ +public class RequestResponseTest { + + private static final String RESPONSE_CONTENTS = "Test response body"; + private static final String REQUEST_CONTENTS = "Test request body"; + private static final String LARGE_REQUEST_CONTENTS = REQUEST_CONTENTS.repeat(32 * 1024); + + private static TestCertificateGenerator.CertificateBundle certBundle; + private static SSLContext clientSslContext; + + private NettyTestServer server; + private HttpClient client; + private RequestCapturingHttp2ClientHandler h2RequestHandler; + private RequestCapturingHttp11ClientHandler h1RequestHandler; + + @BeforeAll + static void beforeAll() throws Exception { + certBundle = TestCertificateGenerator.generateCertificates(); + clientSslContext = TestUtils.createClientSslContext(certBundle); + } + + @BeforeEach + void setUp(TestInfo testInfo) { + // Setup is done in the test method based on config + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + private void setupForConfig(TransportConfig config) throws Exception { + var serverBuilder = NettyTestServer.builder().httpVersion(config.httpVersion()); + + if (config.isHttp2()) { + h2RequestHandler = new RequestCapturingHttp2ClientHandler(); + serverBuilder.h2ConnectionMode(config.h2Mode()) + .http2HandlerFactory(ctx -> new MultiplexingHttp2ClientHandler( + h2RequestHandler, + new TextResponseHttp2ClientHandler(RESPONSE_CONTENTS))); + } else { + h1RequestHandler = new RequestCapturingHttp11ClientHandler(); + serverBuilder.http11HandlerFactory(ctx -> new MultiplexingHttp11ClientHandler( + h1RequestHandler, + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS))); + } + + if (config.useTls()) { + serverBuilder.sslContextBuilder(TestUtils.createServerSslContextBuilder(certBundle)); + } + + server = serverBuilder.build(); + server.start(); + + var clientBuilder = HttpClient.builder() + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(DnsResolver.staticMapping(Map.of("localhost", List.of(InetAddress.getLoopbackAddress())))) + .httpVersionPolicy(config.versionPolicy()); + + if (config.useTls()) { + clientBuilder.sslContext(clientSslContext); + } + + client = clientBuilder.build(); + } + + private String uri(TransportConfig config) { + String scheme = config.useTls() ? "https" : "http"; + return scheme + "://localhost:" + server.getPort(); + } + + private String readBody(HttpResponse response) throws IOException { + try (var body = response.body().asInputStream()) { + return new String(body.readAllBytes(), StandardCharsets.UTF_8); + } + } + + @ParameterizedTest(name = "{0}") + @EnumSource(TransportConfig.class) + void canSendRequestAndReadResponse(TransportConfig config) throws Exception { + setupForConfig(config); + + var request = TestUtils.plainTextRequest(config.httpVersion(), uri(config), REQUEST_CONTENTS); + var response = client.send(request); + var responseBody = readBody(response); + + String capturedBody; + if (config.isHttp2()) { + h2RequestHandler.streamCompleted().join(); + capturedBody = h2RequestHandler.capturedBody().toString(StandardCharsets.UTF_8); + } else { + capturedBody = h1RequestHandler.capturedBody().toString(StandardCharsets.UTF_8); + } + + assertEquals(REQUEST_CONTENTS, capturedBody); + assertEquals(RESPONSE_CONTENTS, responseBody); + } + + @ParameterizedTest(name = "{0}") + @EnumSource(value = TransportConfig.class, names = {"H2C", "H2_TLS", "H2_ALPN"}) + void canSendLargeReplayableRequestAndReadResponse(TransportConfig config) throws Exception { + setupForConfig(config); + + byte[] body = LARGE_REQUEST_CONTENTS.getBytes(StandardCharsets.UTF_8); + var request = HttpRequest.create() + .setMethod("POST") + .setUri(URI.create(uri(config))) + .setHttpVersion(config.httpVersion()) + .setHeaders(HttpHeaders.of(Map.of( + "content-type", + List.of("text/plain"), + "content-length", + List.of(Integer.toString(body.length))))) + .setBody(DataStream.ofByteBuffer(ByteBuffer.wrap(body))); + var response = client.send(request); + var responseBody = readBody(response); + + h2RequestHandler.streamCompleted().join(); + + assertEquals(LARGE_REQUEST_CONTENTS, h2RequestHandler.capturedBody().toString(StandardCharsets.UTF_8)); + assertEquals(RESPONSE_CONTENTS, responseBody); + } + + @ParameterizedTest(name = "{0}") + @EnumSource(value = TransportConfig.class, names = {"H2C", "H2_TLS", "H2_ALPN"}) + void canSendReplayableFileRequestAndReadResponse(TransportConfig config) throws Exception { + setupForConfig(config); + + byte[] body = LARGE_REQUEST_CONTENTS.getBytes(StandardCharsets.UTF_8); + Path tempFile = Files.createTempFile("smithy-http-client-upload", ".txt"); + try { + Files.write(tempFile, body); + + var request = HttpRequest.create() + .setMethod("POST") + .setUri(URI.create(uri(config))) + .setHttpVersion(config.httpVersion()) + .setHeaders(HttpHeaders.of(Map.of( + "content-type", + List.of("text/plain"), + "content-length", + List.of(Integer.toString(body.length))))) + .setBody(DataStream.ofFile(tempFile, "text/plain")); + var response = client.send(request); + var responseBody = readBody(response); + + h2RequestHandler.streamCompleted().join(); + + assertEquals(LARGE_REQUEST_CONTENTS, h2RequestHandler.capturedBody().toString(StandardCharsets.UTF_8)); + assertEquals(RESPONSE_CONTENTS, responseBody); + } finally { + Files.deleteIfExists(tempFile); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestStreamingTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestStreamingTest.java new file mode 100644 index 0000000000..6feb82b712 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/RequestStreamingTest.java @@ -0,0 +1,117 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.smithy.java.http.client.it.TestUtils.IPSUM_LOREM; +import static software.amazon.smithy.java.http.client.it.TestUtils.streamingBody; + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SSLContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.TestCertificateGenerator; +import software.amazon.smithy.java.http.client.it.server.h2.MultiplexingHttp2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.RequestCapturingHttp2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.TextResponseHttp2ClientHandler; + +/** + * Parameterized test for streaming request body across HTTP/2 transport configurations. + */ +public class RequestStreamingTest { + + private static final String RESPONSE_CONTENTS = "Test response body"; + + private static TestCertificateGenerator.CertificateBundle certBundle; + private static SSLContext clientSslContext; + + private NettyTestServer server; + private HttpClient client; + private RequestCapturingHttp2ClientHandler requestHandler; + + @BeforeAll + static void beforeAll() throws Exception { + certBundle = TestCertificateGenerator.generateCertificates(); + clientSslContext = TestUtils.createClientSslContext(certBundle); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + private void setupForConfig(TransportConfig config) throws Exception { + requestHandler = new RequestCapturingHttp2ClientHandler(); + + var serverBuilder = NettyTestServer.builder() + .httpVersion(config.httpVersion()) + .h2ConnectionMode(config.h2Mode()) + .http2HandlerFactory(ctx -> new MultiplexingHttp2ClientHandler( + requestHandler, + new TextResponseHttp2ClientHandler(RESPONSE_CONTENTS))); + + if (config.useTls()) { + serverBuilder.sslContextBuilder(TestUtils.createServerSslContextBuilder(certBundle)); + } + + server = serverBuilder.build(); + server.start(); + + var clientBuilder = HttpClient.builder() + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(DnsResolver.staticMapping(Map.of("localhost", List.of(InetAddress.getLoopbackAddress())))) + .httpVersionPolicy(config.versionPolicy()); + + if (config.useTls()) { + clientBuilder.sslContext(clientSslContext); + } + + client = clientBuilder.build(); + } + + private String uri(TransportConfig config) { + String scheme = config.useTls() ? "https" : "http"; + return scheme + "://localhost:" + server.getPort(); + } + + private String readBody(HttpResponse response) throws IOException { + try (var body = response.body().asInputStream()) { + return new String(body.readAllBytes(), StandardCharsets.UTF_8); + } + } + + @ParameterizedTest(name = "{0}") + @EnumSource(value = TransportConfig.class, names = {"H2C", "H2_TLS", "H2_ALPN"}) + void canSendStreamingRequestAndReadResponse(TransportConfig config) throws Exception { + setupForConfig(config); + + var request = TestUtils.request(config.httpVersion(), uri(config), streamingBody(IPSUM_LOREM)); + var response = client.send(request); + + requestHandler.streamCompleted().join(); + + assertEquals(String.join("", IPSUM_LOREM), requestHandler.capturedBody().toString(StandardCharsets.UTF_8)); + assertEquals(RESPONSE_CONTENTS, readBody(response)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TestUtils.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TestUtils.java new file mode 100644 index 0000000000..e839c36b99 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TestUtils.java @@ -0,0 +1,169 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it; + +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.SslContextBuilder; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.Flow; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.it.server.TestCertificateGenerator; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +public class TestUtils { + public static final List IPSUM_LOREM = getIpsumLorem(); + + private TestUtils() {} + + public static HttpRequest plainTextHttp11Request(String uri, String contents) { + return plainTextRequest(HttpVersion.HTTP_1_1, uri, contents); + } + + public static HttpRequest plainTextHttp2Request(String uri, String contents) { + return plainTextRequest(HttpVersion.HTTP_2, uri, contents); + } + + public static HttpRequest plainTextRequest(HttpVersion version, String uri, String contents) { + return request(version, uri, DataStream.ofString(contents)); + } + + public static DataStream streamingBody(Iterable values) { + return DataStream.ofPublisher(new StreamingPublisher(values), "text/plain", -1); + } + + public static HttpRequest request(HttpVersion version, String uri, DataStream body) { + try { + var headers = HttpHeaders.ofModifiable(); + headers.addHeader("content-type", "text/plain"); + if (body.contentLength() >= 0) { + headers.addHeader("content-length", Long.toString(body.contentLength())); + } else if (version == HttpVersion.HTTP_1_1) { + // HTTP/1.1 needs transfer-encoding for streaming bodies + headers.addHeader("transfer-encoding", "chunked"); + } + return HttpRequest.create() + .setHttpVersion(version) + .setUri(SmithyUri.of(uri)) + .setHeaders(headers) + .setMethod("POST") + .setBody(body); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static SslContextBuilder createServerSslContextBuilder( + TestCertificateGenerator.CertificateBundle bundle + ) throws Exception { + return SslContextBuilder + .forServer(bundle.serverPrivateKey, bundle.serverCertificate) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + "h2", + "http/1.1")); + } + + public static SSLContext createClientSslContext( + TestCertificateGenerator.CertificateBundle bundle + ) throws Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, createTrustManager(bundle.caCertificate), new SecureRandom()); + return sslContext; + } + + public static TrustManager[] createTrustManager(X509Certificate caCert) throws Exception { + // Create a KeyStore and add the CA certificate + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); // Initialize empty keystore + keyStore.setCertificateEntry("ca-cert", caCert); + + // Initialize TrustManagerFactory with the KeyStore + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + + // Return the first TrustManager (typically there's only one) + return tmf.getTrustManagers(); + } + + private static List getIpsumLorem() { + return Arrays.asList( + "Lorem ipsum dolor sit amet, ", + "consectetur adipiscing elit, sed do ", + "eiusmod tempor incididunt ut ", + "labore et dolore magna aliqua. ", + "Ut enim ad minim veniam, quis ", + "nostrud exercitation ullamco laboris ", + "nisi ut ", + "aliquip ex ea commodo consequat. ", + "Duis aute irure dolor in ", + "reprehenderit in voluptate velit esse ", + "cillum dolore eu fugiat nulla ", + "pariatur. Excepteur sint occaecat ", + "cupidatat non proident, sunt in ", + "culpa qui officia deserunt mollit ", + "anim id est laborum."); + } + + static class StreamingPublisher implements Flow.Publisher { + private final Iterable values; + + StreamingPublisher(Iterable values) { + this.values = values; + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + subscriber.onSubscribe(new StreamingSubscription(values, subscriber)); + } + } + + static class StreamingSubscription implements Flow.Subscription { + private final Iterator values; + private final Flow.Subscriber subscriber; + private boolean completed = false; + + StreamingSubscription(Iterable values, Flow.Subscriber subscriber) { + this.values = values.iterator(); + this.subscriber = subscriber; + } + + @Override + public void request(long n) { + if (completed) { + return; + } + for (var idx = 0; idx < n && values.hasNext(); idx++) { + var value = ByteBuffer.wrap(values.next().getBytes(StandardCharsets.UTF_8)); + subscriber.onNext(value); + } + if (!values.hasNext()) { + completed = true; + subscriber.onComplete(); + } + } + + @Override + public void cancel() { + subscriber.onComplete(); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TlsValidationTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TlsValidationTest.java new file mode 100644 index 0000000000..f78bf32023 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TlsValidationTest.java @@ -0,0 +1,317 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import io.netty.handler.ssl.SslContextBuilder; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.SocketException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.Date; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.TestCertificateGenerator; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests TLS certificate validation edge cases. + */ +public class TlsValidationTest { + + private static TestCertificateGenerator.CertificateBundle validBundle; + private NettyTestServer server; + private HttpClient client; + + @BeforeAll + static void beforeAll() throws Exception { + validBundle = TestCertificateGenerator.generateCertificates(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + @Test + void rejectsUntrustedCertificate() throws Exception { + // Server uses valid cert, but client doesn't trust the CA + server = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler("response")) + .sslContextBuilder(SslContextBuilder.forServer( + validBundle.serverPrivateKey, + validBundle.serverCertificate)) + .build(); + server.start(); + + // Client with empty trust store (doesn't trust any CA) + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new SecureRandom()); // Default trust manager won't trust test CA + + client = createClient(sslContext); + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, + "https://localhost:" + server.getPort(), + ""); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTlsFailure(ex); + } + + @Test + void rejectsWrongHostname() throws Exception { + // Generate cert for "wronghost.example.com" instead of "localhost" + var wrongHostBundle = generateCertForHost("wronghost.example.com"); + + server = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler("response")) + .sslContextBuilder(SslContextBuilder.forServer( + wrongHostBundle.serverPrivateKey, + wrongHostBundle.serverCertificate)) + .build(); + server.start(); + + // Client trusts the CA but hostname won't match + client = createClient(createTrustingSslContext(wrongHostBundle.caCertificate)); + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, + "https://localhost:" + server.getPort(), + ""); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTlsFailure(ex); + } + + @Test + void rejectsExpiredCertificate() throws Exception { + // Generate expired cert + var expiredBundle = generateExpiredCert(); + + server = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler("response")) + .sslContextBuilder(SslContextBuilder.forServer( + expiredBundle.serverPrivateKey, + expiredBundle.serverCertificate)) + .build(); + server.start(); + + client = createClient(createTrustingSslContext(expiredBundle.caCertificate)); + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, + "https://localhost:" + server.getPort(), + ""); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTlsFailure(ex); + } + + @Test + void rejectsSelfSignedCertificate() throws Exception { + // Generate self-signed cert (no CA) + var selfSignedCert = generateSelfSignedCert(); + + server = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler("response")) + .sslContextBuilder(SslContextBuilder.forServer( + selfSignedCert.privateKey, + selfSignedCert.certificate)) + .build(); + server.start(); + + // Client with default trust store (won't trust self-signed) + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new SecureRandom()); + + client = createClient(sslContext); + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, + "https://localhost:" + server.getPort(), + ""); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTlsFailure(ex); + } + + private void assertTlsFailure(Throwable ex) { + // TLS failures can manifest as SSLHandshakeException or SocketException (socket closed by peer) + // depending on timing of when the failure is detected + Throwable current = ex; + while (current != null) { + if (current instanceof SSLHandshakeException + || (current instanceof SocketException + && current.getMessage() != null + && current.getMessage().contains("closed"))) { + return; + } + current = current.getCause(); + } + throw new AssertionError("Expected TLS failure (SSLHandshakeException or SocketException) but not found in: " + + ex, ex); + } + + private HttpClient createClient(SSLContext sslContext) { + DnsResolver staticDns = DnsResolver.staticMapping(Map.of( + "localhost", + List.of(InetAddress.getLoopbackAddress()))); + return HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(staticDns) + .sslContext(sslContext) + .build(); + } + + private SSLContext createTrustingSslContext(X509Certificate caCert) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + keyStore.setCertificateEntry("ca-cert", caCert); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); + return sslContext; + } + + private TestCertificateGenerator.CertificateBundle generateCertForHost(String hostname) throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + + KeyPair caKeyPair = keyGen.generateKeyPair(); + X509Certificate caCert = generateCA(caKeyPair); + + KeyPair serverKeyPair = keyGen.generateKeyPair(); + X509Certificate serverCert = generateServerCert(serverKeyPair, + caKeyPair, + caCert, + hostname, + new Date(), + new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000)); + + return new TestCertificateGenerator.CertificateBundle(caCert, serverCert, serverKeyPair.getPrivate()); + } + + private TestCertificateGenerator.CertificateBundle generateExpiredCert() throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + + KeyPair caKeyPair = keyGen.generateKeyPair(); + X509Certificate caCert = generateCA(caKeyPair); + + KeyPair serverKeyPair = keyGen.generateKeyPair(); + // Expired: notBefore and notAfter both in the past + Date notBefore = new Date(System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000); + Date notAfter = new Date(System.currentTimeMillis() - 1 * 24 * 60 * 60 * 1000); + X509Certificate serverCert = generateServerCert(serverKeyPair, + caKeyPair, + caCert, + "localhost", + notBefore, + notAfter); + + return new TestCertificateGenerator.CertificateBundle(caCert, serverCert, serverKeyPair.getPrivate()); + } + + private SelfSignedCert generateSelfSignedCert() throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair keyPair = keyGen.generateKeyPair(); + + var subject = new X500Name("CN=localhost, O=Test, C=US"); + var certBuilder = new JcaX509v3CertificateBuilder( + subject, + BigInteger.valueOf(System.currentTimeMillis()), + new Date(), + new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000), + subject, + keyPair.getPublic()); + + var signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()); + var cert = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer)); + + return new SelfSignedCert(cert, keyPair.getPrivate()); + } + + private X509Certificate generateCA(KeyPair keyPair) throws Exception { + var issuer = new X500Name("CN=Test CA, O=Test, C=US"); + var certBuilder = new JcaX509v3CertificateBuilder( + issuer, + BigInteger.valueOf(System.currentTimeMillis()), + new Date(), + new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000), + issuer, + keyPair.getPublic()) + .addExtension(Extension.basicConstraints, true, new BasicConstraints(true)) + .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign)); + + var signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()); + return new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer)); + } + + private X509Certificate generateServerCert( + KeyPair serverKeyPair, + KeyPair caKeyPair, + X509Certificate caCert, + String hostname, + Date notBefore, + Date notAfter + ) throws Exception { + var issuer = X500Name.getInstance(caCert.getSubjectX500Principal().getEncoded()); + var subject = new X500Name("CN=" + hostname + ", O=Test, C=US"); + + var sanNames = new GeneralName[] {new GeneralName(GeneralName.dNSName, hostname)}; + + var certBuilder = new JcaX509v3CertificateBuilder( + issuer, + BigInteger.valueOf(System.currentTimeMillis()), + notBefore, + notAfter, + subject, + serverKeyPair.getPublic()) + .addExtension(Extension.subjectAlternativeName, false, new GeneralNames(sanNames)); + + var signer = new JcaContentSignerBuilder("SHA256withRSA").build(caKeyPair.getPrivate()); + return new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer)); + } + + private record SelfSignedCert(X509Certificate certificate, PrivateKey privateKey) {} +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TransportConfig.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TransportConfig.java new file mode 100644 index 0000000000..d34d8b6f09 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/TransportConfig.java @@ -0,0 +1,53 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it; + +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer.H2ConnectionMode; + +/** + * Transport configurations for parameterized HTTP client tests. + */ +public enum TransportConfig { + H1_CLEAR(HttpVersion.HTTP_1_1, false, null, HttpVersionPolicy.ENFORCE_HTTP_1_1), + H1_TLS(HttpVersion.HTTP_1_1, true, null, HttpVersionPolicy.ENFORCE_HTTP_1_1), + H2C(HttpVersion.HTTP_2, false, H2ConnectionMode.PRIOR_KNOWLEDGE, HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE), + H2_TLS(HttpVersion.HTTP_2, true, H2ConnectionMode.PRIOR_KNOWLEDGE, HttpVersionPolicy.ENFORCE_HTTP_2), + H2_ALPN(HttpVersion.HTTP_2, true, H2ConnectionMode.ALPN, HttpVersionPolicy.AUTOMATIC); + + private final HttpVersion httpVersion; + private final boolean useTls; + private final H2ConnectionMode h2Mode; + private final HttpVersionPolicy versionPolicy; + + TransportConfig(HttpVersion httpVersion, boolean useTls, H2ConnectionMode h2Mode, HttpVersionPolicy versionPolicy) { + this.httpVersion = httpVersion; + this.useTls = useTls; + this.h2Mode = h2Mode; + this.versionPolicy = versionPolicy; + } + + public HttpVersion httpVersion() { + return httpVersion; + } + + public boolean useTls() { + return useTls; + } + + public H2ConnectionMode h2Mode() { + return h2Mode; + } + + public HttpVersionPolicy versionPolicy() { + return versionPolicy; + } + + public boolean isHttp2() { + return httpVersion == HttpVersion.HTTP_2; + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/BaseHttpClientIntegTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/BaseHttpClientIntegTest.java new file mode 100644 index 0000000000..aaa4cc3f50 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/BaseHttpClientIntegTest.java @@ -0,0 +1,91 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; + +/** + * Base class for HTTP client integration tests. + * Provides common setup/teardown and utility methods. + */ +public abstract class BaseHttpClientIntegTest { + + protected static final String RESPONSE_CONTENTS = "Test response body"; + protected static final String REQUEST_CONTENTS = "Test request body"; + + protected NettyTestServer server; + protected HttpClient client; + + /** + * Configure the test server. + */ + protected abstract NettyTestServer.Builder configureServer(NettyTestServer.Builder builder); + + /** + * Configure the HTTP client. + */ + protected abstract HttpClient.Builder configureClient(HttpClient.Builder builder); + + @BeforeEach + void setUp() throws Exception { + server = configureServer(NettyTestServer.builder()).build(); + server.start(); + + DnsResolver staticDns = DnsResolver.staticMapping(Map.of( + "localhost", + List.of(InetAddress.getLoopbackAddress()))); + + var clientBuilder = HttpClient.builder() + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(staticDns); + + client = configureClient(clientBuilder).build(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + protected String uri(String path) { + return "http://localhost:" + server.getPort() + path; + } + + protected String uri() { + return uri(""); + } + + protected HttpRequest plainTextRequest(HttpVersion version, String body) { + return TestUtils.plainTextRequest(version, uri(), body); + } + + protected String readBody(HttpResponse response) throws IOException { + try (var body = response.body().asInputStream()) { + return new String(body.readAllBytes(), StandardCharsets.UTF_8); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedRequestHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedRequestHttp11Test.java new file mode 100644 index 0000000000..fc1f625893 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedRequestHttp11Test.java @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.smithy.java.http.client.it.TestUtils.IPSUM_LOREM; +import static software.amazon.smithy.java.http.client.it.TestUtils.streamingBody; + +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.MultiplexingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.RequestCapturingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests HTTP/1.1 chunked transfer encoding for request body. + */ +public class ChunkedRequestHttp11Test extends BaseHttpClientIntegTest { + + private RequestCapturingHttp11ClientHandler requestCapturingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + requestCapturingHandler = new RequestCapturingHttp11ClientHandler(); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new MultiplexingHttp11ClientHandler( + requestCapturingHandler, + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS))); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void canSendChunkedRequestBody() throws Exception { + // streamingBody has unknown content length (-1), so it will use chunked encoding + var request = TestUtils.request(HttpVersion.HTTP_1_1, uri(), streamingBody(IPSUM_LOREM)); + + var response = client.send(request); + var responseBody = readBody(response); + + assertEquals(String.join("", IPSUM_LOREM), + requestCapturingHandler.capturedBody().toString(StandardCharsets.UTF_8)); + assertEquals(RESPONSE_CONTENTS, responseBody); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedResponseHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedResponseHttp11Test.java new file mode 100644 index 0000000000..19d825b7fd --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ChunkedResponseHttp11Test.java @@ -0,0 +1,44 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ChunkedResponseHttp11ClientHandler; + +/** + * Tests HTTP/1.1 chunked transfer encoding response. + */ +public class ChunkedResponseHttp11Test extends BaseHttpClientIntegTest { + + private static final List CHUNKS = List.of("Hello ", "chunked ", "world!"); + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new ChunkedResponseHttp11ClientHandler(CHUNKS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void readsChunkedTransferEncodingResponse() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + + assertEquals(String.join("", CHUNKS), readBody(response)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectTimeoutHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectTimeoutHttp11Test.java new file mode 100644 index 0000000000..0a95ba279e --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectTimeoutHttp11Test.java @@ -0,0 +1,47 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that connection timeout throws SocketTimeoutException. + */ +public class ConnectTimeoutHttp11Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + // Server exists but we'll connect to a non-routable IP + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .connectTimeout(Duration.ofMillis(100)); // Very short timeout + } + + @Test + void connectTimeoutThrowsException() { + // Use non-routable IP address (RFC 5737 TEST-NET-1) to trigger connect timeout + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, "http://192.0.2.1:12345", ""); + + assertThrows(IOException.class, () -> client.send(request)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionCloseHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionCloseHttp11Test.java new file mode 100644 index 0000000000..d8d72660ec --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionCloseHttp11Test.java @@ -0,0 +1,52 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionCloseHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionTrackingHttp11ClientHandler; + +/** + * Tests that Connection: close header prevents connection reuse. + */ +public class ConnectionCloseHttp11Test extends BaseHttpClientIntegTest { + + private ConnectionTrackingHttp11ClientHandler trackingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + trackingHandler = new ConnectionTrackingHttp11ClientHandler( + new ConnectionCloseHttp11ClientHandler(RESPONSE_CONTENTS)); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> trackingHandler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void connectionNotReusedWhenServerSendsClose() throws Exception { + // Send two requests + for (int i = 0; i < 2; i++) { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + assertEquals(RESPONSE_CONTENTS, readBody(response)); + } + + // Each request should use a new connection since server sends Connection: close + assertEquals(2, trackingHandler.requestCount()); + assertEquals(2, trackingHandler.connectionCount(), "Should create new connection for each request"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolExhaustionHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolExhaustionHttp11Test.java new file mode 100644 index 0000000000..86f5dfffe3 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolExhaustionHttp11Test.java @@ -0,0 +1,73 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.DelayedResponseHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that requests block when connection pool is exhausted, then succeed. + */ +public class ConnectionPoolExhaustionHttp11Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new DelayedResponseHttp11ClientHandler( + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS), + 200)); // 200ms delay + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(1); // Only 1 connection allowed per route + } + + @Test + void blocksWhenPoolExhaustedThenSucceeds() throws Exception { + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + // First request holds the only connection for 200ms + var future1 = CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + return readBody(response); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor); + + // Small delay to ensure first request acquires connection + Thread.sleep(50); + + // Second request must wait for first to complete + var future2 = CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + return readBody(response); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor); + + assertEquals(RESPONSE_CONTENTS, future1.join()); + assertEquals(RESPONSE_CONTENTS, future2.join()); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolHighConcurrencyReuseTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolHighConcurrencyReuseTest.java new file mode 100644 index 0000000000..c34452c4dd --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolHighConcurrencyReuseTest.java @@ -0,0 +1,90 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionTrackingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that HTTP/1.1 connections are properly reused under high concurrency + * when concurrency exceeds maxConnections. + * + *

This tests the fix for a race condition where threads waiting on acquirePermit() + * would create new connections instead of reusing ones released while waiting. + */ +public class ConnectionPoolHighConcurrencyReuseTest extends BaseHttpClientIntegTest { + + private static final int MAX_CONNECTIONS = 5; + private static final int CONCURRENCY = 50; + private static final int REQUESTS_PER_THREAD = 10; + + private ConnectionTrackingHttp11ClientHandler trackingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + trackingHandler = new ConnectionTrackingHttp11ClientHandler( + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS)); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> trackingHandler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(MAX_CONNECTIONS) + .maxTotalConnections(MAX_CONNECTIONS); + } + + @Test + void connectionsAreReusedUnderHighConcurrency() throws Exception { + int totalRequests = CONCURRENCY * REQUESTS_PER_THREAD; + var successCount = new AtomicInteger(0); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + var futures = new CompletableFuture[CONCURRENCY]; + + for (int i = 0; i < CONCURRENCY; i++) { + futures[i] = CompletableFuture.runAsync(() -> { + for (int j = 0; j < REQUESTS_PER_THREAD; j++) { + try { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + if (RESPONSE_CONTENTS.equals(readBody(response))) { + successCount.incrementAndGet(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, executor); + } + + CompletableFuture.allOf(futures).join(); + } + + assertEquals(totalRequests, successCount.get(), "All requests should succeed"); + assertEquals(totalRequests, trackingHandler.requestCount(), "Server should receive all requests"); + + // Connections should be reused, not created for every request. + // We should have at most maxConnections connections. + int connectionCount = trackingHandler.connectionCount(); + assertTrue(connectionCount <= MAX_CONNECTIONS, + "Should create at most " + MAX_CONNECTIONS + " connections, but created " + connectionCount); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolReuseHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolReuseHttp11Test.java new file mode 100644 index 0000000000..87d9f5be21 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ConnectionPoolReuseHttp11Test.java @@ -0,0 +1,54 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionTrackingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that HTTP/1.1 connections are reused across multiple requests. + */ +public class ConnectionPoolReuseHttp11Test extends BaseHttpClientIntegTest { + + private static final int NUM_REQUESTS = 5; + + private ConnectionTrackingHttp11ClientHandler trackingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + trackingHandler = new ConnectionTrackingHttp11ClientHandler( + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS)); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> trackingHandler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(1); + } + + @Test + void connectionIsReusedForMultipleRequests() throws Exception { + for (int i = 0; i < NUM_REQUESTS; i++) { + var request = plainTextRequest(HttpVersion.HTTP_1_1, REQUEST_CONTENTS); + var response = client.send(request); + assertEquals(RESPONSE_CONTENTS, readBody(response)); + } + + assertEquals(NUM_REQUESTS, trackingHandler.requestCount(), "Should have received all requests"); + assertEquals(1, trackingHandler.connectionCount(), "Should reuse single connection"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContentLengthRequestHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContentLengthRequestHttp11Test.java new file mode 100644 index 0000000000..df0ec8bc37 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContentLengthRequestHttp11Test.java @@ -0,0 +1,131 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.util.CharsetUtil; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.Http11ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Tests HTTP/1.1 request body with Content-Length (non-chunked). + */ +public class ContentLengthRequestHttp11Test extends BaseHttpClientIntegTest { + + private CapturingHandler handler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + handler = new CapturingHandler(); + return builder + .httpVersion(software.amazon.smithy.java.http.api.HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> handler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void sendsRequestBodyWithContentLength() throws Exception { + var headers = HttpHeaders.ofModifiable(); + headers.addHeader("content-type", "text/plain"); + headers.addHeader("content-length", String.valueOf(REQUEST_CONTENTS.length())); + + var request = HttpRequest.create() + .setHttpVersion(software.amazon.smithy.java.http.api.HttpVersion.HTTP_1_1) + .setUri(SmithyUri.of(uri())) + .setMethod("POST") + .setHeaders(headers) + .setBody(DataStream.ofString(REQUEST_CONTENTS)); + + var response = client.send(request); + + assertEquals(200, response.statusCode()); + assertEquals(RESPONSE_CONTENTS, readBody(response)); + assertEquals(REQUEST_CONTENTS, handler.capturedBody.toString(StandardCharsets.UTF_8)); + + // Verify Content-Length was sent (not chunked) + assertTrue(handler.capturedHeaders.containsKey("content-length") + || handler.capturedHeaders.containsKey("Content-Length")); + } + + @Test + void sendsLargeRequestBodyWithContentLength() throws Exception { + // 100KB body + String largeBody = "x".repeat(100 * 1024); + + var headers = HttpHeaders.ofModifiable(); + headers.addHeader("content-type", "text/plain"); + headers.addHeader("content-length", String.valueOf(largeBody.length())); + + var request = HttpRequest.create() + .setHttpVersion(software.amazon.smithy.java.http.api.HttpVersion.HTTP_1_1) + .setUri(SmithyUri.of(uri())) + .setMethod("POST") + .setHeaders(headers) + .setBody(DataStream.ofString(largeBody)); + + var response = client.send(request); + + assertEquals(200, response.statusCode()); + assertEquals(largeBody, handler.capturedBody.toString(StandardCharsets.UTF_8)); + } + + static class CapturingHandler implements Http11ClientHandler { + final Map> capturedHeaders = new HashMap<>(); + final ByteArrayOutputStream capturedBody = new ByteArrayOutputStream(); + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + // Capture headers + for (var entry : request.headers()) { + capturedHeaders.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue()); + } + // Capture body + var content = request.content(); + var bytes = new byte[content.readableBytes()]; + content.getBytes(content.readerIndex(), bytes); + try { + capturedBody.write(bytes); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // Send response + var responseContent = Unpooled.copiedBuffer(RESPONSE_CONTENTS, CharsetUtil.UTF_8); + var response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, responseContent); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, responseContent.readableBytes()); + response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + ctx.writeAndFlush(response); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContinueHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContinueHttp11Test.java new file mode 100644 index 0000000000..9e75cd58e1 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ContinueHttp11Test.java @@ -0,0 +1,61 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ContinueHttp11ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Tests HTTP/1.1 100-continue handling. + */ +public class ContinueHttp11Test extends BaseHttpClientIntegTest { + + private ContinueHttp11ClientHandler handler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + handler = new ContinueHttp11ClientHandler(RESPONSE_CONTENTS); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> handler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void handles100ContinueCorrectly() throws Exception { + var headers = HttpHeaders.ofModifiable(); + headers.addHeader("content-type", "text/plain"); + headers.addHeader("expect", "100-continue"); + headers.addHeader("content-length", String.valueOf(REQUEST_CONTENTS.length())); + + var request = HttpRequest.create() + .setHttpVersion(HttpVersion.HTTP_1_1) + .setUri(SmithyUri.of(uri())) + .setMethod("POST") + .setHeaders(headers) + .setBody(DataStream.ofString(REQUEST_CONTENTS)); + + var response = client.send(request); + + assertEquals(RESPONSE_CONTENTS, readBody(response)); + assertEquals(REQUEST_CONTENTS, handler.capturedBody().toString(StandardCharsets.UTF_8)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/EmptyBodyHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/EmptyBodyHttp11Test.java new file mode 100644 index 0000000000..f6ab837fce --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/EmptyBodyHttp11Test.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.EmptyResponseHttp11ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Tests empty request and response bodies. + */ +public class EmptyBodyHttp11Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new EmptyResponseHttp11ClientHandler()); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void handlesEmptyRequestAndResponseBody() throws Exception { + // Request with no body + var request = HttpRequest.create() + .setHttpVersion(HttpVersion.HTTP_1_1) + .setUri(SmithyUri.of(uri())) + .setMethod("GET") + .setHeaders(HttpHeaders.ofModifiable()) + .setBody(DataStream.ofEmpty()); + + var response = client.send(request); + + assertEquals(204, response.statusCode()); + assertEquals("", readBody(response)); + } + + @Test + void handlesPostWithEmptyBody() throws Exception { + var headers = HttpHeaders.ofModifiable(); + headers.addHeader("content-length", "0"); + + var request = HttpRequest.create() + .setHttpVersion(HttpVersion.HTTP_1_1) + .setUri(SmithyUri.of(uri())) + .setMethod("POST") + .setHeaders(headers) + .setBody(DataStream.ofEmpty()); + + var response = client.send(request); + + assertEquals(204, response.statusCode()); + assertEquals("", readBody(response)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/HighConcurrencyHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/HighConcurrencyHttp11Test.java new file mode 100644 index 0000000000..1c93dccfb4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/HighConcurrencyHttp11Test.java @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Stress test with many concurrent HTTP/1.1 requests. + * Tests various pool sizes to verify connection reuse and permit release. + */ +public class HighConcurrencyHttp11Test extends BaseHttpClientIntegTest { + + // Set by parameterized test + private int poolSize = 20; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(poolSize) + .maxTotalConnections(poolSize); + } + + static Stream poolConfigurations() { + return Stream.of( + // poolSize, numRequests - tests connection reuse when requests > pool + Arguments.of(5, 50), // 10x reuse required + Arguments.of(10, 100), // 10x reuse required + Arguments.of(20, 100), // 5x reuse required + Arguments.of(50, 100) // 2x reuse required + ); + } + + @ParameterizedTest(name = "pool={0}, requests={1}") + @MethodSource("poolConfigurations") + void handlesMoreRequestsThanPoolSize(int poolSize, int numRequests) throws Exception { + this.poolSize = poolSize; + + // Recreate client with new pool size + if (client != null) { + client.close(); + } + setUp(); + + var futures = new ArrayList>(); + var successCount = new AtomicInteger(); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + for (int i = 0; i < numRequests; i++) { + futures.add(CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + var body = readBody(response); + successCount.incrementAndGet(); + return body; + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor)); + } + + for (var future : futures) { + assertEquals(RESPONSE_CONTENTS, future.join()); + } + } + + assertEquals(numRequests, successCount.get()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/IdleConnectionCleanupHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/IdleConnectionCleanupHttp11Test.java new file mode 100644 index 0000000000..8a121c3859 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/IdleConnectionCleanupHttp11Test.java @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionTrackingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that idle connections are cleaned up after timeout. + */ +public class IdleConnectionCleanupHttp11Test extends BaseHttpClientIntegTest { + + private ConnectionTrackingHttp11ClientHandler trackingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + trackingHandler = new ConnectionTrackingHttp11ClientHandler( + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS)); + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> trackingHandler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxIdleTime(Duration.ofMillis(100)); // Very short idle timeout + } + + @Test + void idleConnectionsAreCleanedUp() throws Exception { + // First request creates connection + var request1 = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response1 = client.send(request1); + assertEquals(RESPONSE_CONTENTS, readBody(response1)); + assertEquals(1, trackingHandler.connectionCount()); + + // Wait for idle timeout + cleanup interval + Thread.sleep(300); + + // Second request should create new connection (old one was cleaned up) + var request2 = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response2 = client.send(request2); + assertEquals(RESPONSE_CONTENTS, readBody(response2)); + + assertEquals(2, trackingHandler.connectionCount(), "Should create new connection after idle cleanup"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/LargeHeadersHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/LargeHeadersHttp11Test.java new file mode 100644 index 0000000000..163087ab0b --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/LargeHeadersHttp11Test.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.LargeHeadersHttp11ClientHandler; + +/** + * Tests handling of responses with many large headers. + */ +public class LargeHeadersHttp11Test extends BaseHttpClientIntegTest { + + private static final int HEADER_COUNT = 50; + private static final int HEADER_VALUE_SIZE = 1000; // 1KB per header value + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new LargeHeadersHttp11ClientHandler( + RESPONSE_CONTENTS, + HEADER_COUNT, + HEADER_VALUE_SIZE)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void handlesLargeResponseHeaders() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + var response = client.send(request); + + assertEquals(RESPONSE_CONTENTS, readBody(response)); + + // Verify at least one large header was received + String value = response.headers().firstValue("x-large-header-0"); + assertEquals(HEADER_VALUE_SIZE, value.length()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/PerRouteLimitsHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/PerRouteLimitsHttp11Test.java new file mode 100644 index 0000000000..db777726f6 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/PerRouteLimitsHttp11Test.java @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.ConnectionTrackingHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that per-route connection limits are independent. + */ +public class PerRouteLimitsHttp11Test { + + private NettyTestServer server1; + private NettyTestServer server2; + private HttpClient client; + private ConnectionTrackingHttp11ClientHandler handler1; + private ConnectionTrackingHttp11ClientHandler handler2; + + @BeforeEach + void setUp() throws Exception { + handler1 = new ConnectionTrackingHttp11ClientHandler( + new TextResponseHttp11ClientHandler("response1")); + handler2 = new ConnectionTrackingHttp11ClientHandler( + new TextResponseHttp11ClientHandler("response2")); + + server1 = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> handler1) + .build(); + server1.start(); + + server2 = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> handler2) + .build(); + server2.start(); + + // Map different hostnames to loopback + DnsResolver staticDns = DnsResolver.staticMapping(Map.of( + "host1.test", + List.of(InetAddress.getLoopbackAddress()), + "host2.test", + List.of(InetAddress.getLoopbackAddress()))); + + client = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(1) // Only 1 connection per route + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(staticDns) + .build(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server1 != null) { + server1.stop(); + } + if (server2 != null) { + server2.stop(); + } + } + + @Test + void differentRoutesHaveIndependentLimits() throws Exception { + // Send request to host1 + var request1 = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, "http://host1.test:" + server1.getPort(), ""); + var response1 = client.send(request1); + assertEquals("response1", readBody(response1)); + + // Send request to host2 - should work even though host1 has a connection + var request2 = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, "http://host2.test:" + server2.getPort(), ""); + var response2 = client.send(request2); + assertEquals("response2", readBody(response2)); + + // Both routes should have 1 connection each + assertEquals(1, handler1.connectionCount()); + assertEquals(1, handler2.connectionCount()); + } + + private String readBody(HttpResponse response) { + var buf = response.body().asByteBuffer(); + var bytes = new byte[buf.remaining()]; + buf.get(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ReadTimeoutHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ReadTimeoutHttp11Test.java new file mode 100644 index 0000000000..ba75d9e942 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ReadTimeoutHttp11Test.java @@ -0,0 +1,47 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.net.SocketTimeoutException; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.DelayedResponseHttp11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.TextResponseHttp11ClientHandler; + +/** + * Tests that read timeout throws SocketTimeoutException. + */ +public class ReadTimeoutHttp11Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new DelayedResponseHttp11ClientHandler( + new TextResponseHttp11ClientHandler(RESPONSE_CONTENTS), + 2000)); // 2s delay + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .readTimeout(Duration.ofMillis(100)); // 100ms timeout, server delays 2s + } + + @Test + void readTimeoutThrowsException() { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + + assertThrows(SocketTimeoutException.class, () -> client.send(request)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ServerCloseMidResponseHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ServerCloseMidResponseHttp11Test.java new file mode 100644 index 0000000000..6cdb1af0c3 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/ServerCloseMidResponseHttp11Test.java @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.connection.CloseReason; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.PartialResponseHttp11ClientHandler; + +/** + * Tests client handling when server closes connection mid-response. + */ +public class ServerCloseMidResponseHttp11Test extends BaseHttpClientIntegTest { + + private final AtomicInteger connectCount = new AtomicInteger(); + private final AtomicInteger closeCount = new AtomicInteger(); + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + // Server advertises 1000 bytes but only sends 10, then closes + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new PartialResponseHttp11ClientHandler("partial...", 1000)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .addListener(new HttpClientListener() { + @Override + public void onConnectionCreated(HttpConnection conn) { + connectCount.incrementAndGet(); + } + + @Override + public void onConnectionClosed(HttpConnection conn, CloseReason reason) { + closeCount.incrementAndGet(); + } + }); + } + + @Test + void throwsWhenServerClosesBeforeFullResponse() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + + var response = client.send(request); + + // Reading the body should fail because server closed before sending full content + var ex = assertThrows(IOException.class, () -> readBody(response)); + assertTrue( + ex.getMessage().contains("end of stream") + || ex.getMessage().contains("EOF") + || ex.getMessage().contains("closed") + || ex.getMessage().contains("Unexpected"), + "Expected EOF-related error, got: " + ex.getMessage()); + + // Connection should have been created + assertEquals(1, connectCount.get(), "Should have created 1 connection"); + + // Connection should be closed/evicted, not returned to pool + assertEquals(1, closeCount.get(), "Connection should be closed after truncated response"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/StatusCodesHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/StatusCodesHttp11Test.java new file mode 100644 index 0000000000..fd17e2c14f --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/StatusCodesHttp11Test.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.InetAddress; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.StatusCodeHttp11ClientHandler; + +/** + * Tests various HTTP status codes. + */ +public class StatusCodesHttp11Test { + + private HttpClient client; + private NettyTestServer server; + + @BeforeEach + void setUp() { + client = HttpClient.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(DnsResolver.staticMapping(Map.of( + "localhost", + List.of(InetAddress.getLoopbackAddress())))) + .build(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + @ParameterizedTest(name = "status {0}") + @ValueSource(ints = {200, 204, 304, 404, 500}) + void handlesStatusCode(int statusCode) throws Exception { + server = NettyTestServer.builder() + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new StatusCodeHttp11ClientHandler(statusCode)) + .build(); + server.start(); + + var request = TestUtils.plainTextRequest(HttpVersion.HTTP_1_1, "http://localhost:" + server.getPort(), ""); + var response = client.send(request); + + assertEquals(statusCode, response.statusCode()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/TrailerHeadersHttp11Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/TrailerHeadersHttp11Test.java new file mode 100644 index 0000000000..bb66f0ba74 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h1/TrailerHeadersHttp11Test.java @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.api.TrailerSupport; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h1.TrailerResponseHttp11ClientHandler; + +/** + * Tests HTTP/1.1 chunked response with trailer headers. + */ +public class TrailerHeadersHttp11Test extends BaseHttpClientIntegTest { + + private static final Map TRAILERS = Map.of( + "x-checksum", + "abc123", + "x-request-id", + "req-456"); + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_1_1) + .http11HandlerFactory(ctx -> new TrailerResponseHttp11ClientHandler(RESPONSE_CONTENTS, TRAILERS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1); + } + + @Test + void readsChunkedResponseWithTrailers() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_1_1, ""); + try (var response = client.send(request)) { + var body = response.body(); + var content = new String(body.asInputStream().readAllBytes()); + assertEquals(RESPONSE_CONTENTS, content); + + if (body instanceof TrailerSupport ts) { + var trailers = ts.trailerHeaders(); + assertNotNull(trailers, "Should have trailer headers"); + assertEquals("abc123", trailers.firstValue("x-checksum")); + assertEquals("req-456", trailers.firstValue("x-request-id")); + } else { + fail("Response body should implement TrailerSupport"); + } + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BaseHttpClientIntegTest.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BaseHttpClientIntegTest.java new file mode 100644 index 0000000000..72c26aa7fa --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BaseHttpClientIntegTest.java @@ -0,0 +1,91 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; + +/** + * Base class for HTTP client integration tests. + * Provides common setup/teardown and utility methods. + */ +public abstract class BaseHttpClientIntegTest { + + protected static final String RESPONSE_CONTENTS = "Test response body"; + protected static final String REQUEST_CONTENTS = "Test request body"; + + protected NettyTestServer server; + protected HttpClient client; + + /** + * Configure the test server. + */ + protected abstract NettyTestServer.Builder configureServer(NettyTestServer.Builder builder); + + /** + * Configure the HTTP client. + */ + protected abstract HttpClient.Builder configureClient(HttpClient.Builder builder); + + @BeforeEach + void setUp() throws Exception { + server = configureServer(NettyTestServer.builder()).build(); + server.start(); + + DnsResolver staticDns = DnsResolver.staticMapping(Map.of( + "localhost", + List.of(InetAddress.getLoopbackAddress()))); + + var clientBuilder = HttpClient.builder() + .maxConnectionsPerRoute(10) + .maxTotalConnections(10) + .maxIdleTime(Duration.ofMinutes(1)) + .dnsResolver(staticDns); + + client = configureClient(clientBuilder).build(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.close(); + } + if (server != null) { + server.stop(); + } + } + + protected String uri(String path) { + return "http://localhost:" + server.getPort() + path; + } + + protected String uri() { + return uri(""); + } + + protected HttpRequest plainTextRequest(HttpVersion version, String body) { + return TestUtils.plainTextRequest(version, uri(), body); + } + + protected String readBody(HttpResponse response) throws IOException { + try (var body = response.body().asInputStream()) { + return new String(body.readAllBytes(), StandardCharsets.UTF_8); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BidirectionalStreamingHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BidirectionalStreamingHttp2Test.java new file mode 100644 index 0000000000..60081295df --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/BidirectionalStreamingHttp2Test.java @@ -0,0 +1,166 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.EchoHttp2ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Proves true HTTP/2 bidirectional (full-duplex) streaming: the response is read while the request body is + * still open and unfinished. + * + *

The request body ({@link BlockingInputStream}) hands over a leading payload then blocks indefinitely, + * unblocking only after the test releases it, which the test does only after {@code client.send(...)} has + * returned and the leading echo has been read. The server ({@link EchoHttp2ClientHandler}) sends response + * HEADERS on the request HEADERS and echoes each request DATA frame back. + * + *

Verified discriminator: the client writes the request body on a background virtual thread (see + * {@code DefaultHttpClient.sendForRoute}), so {@code send()} returns on the response HEADERS while the body + * is still blocked. Forcing the inline-write path instead makes {@code send()} block in the body write + * forever and the test times out. + */ +public class BidirectionalStreamingHttp2Test extends BaseHttpClientIntegTest { + + // Larger than the 16 KB H2 frame buffer so the client flushes a DATA frame for it before the body + // blocks (an OutputStream-backed body only auto-flushes once its frame buffer fills). Position- + // dependent bytes catch a truncated or misordered echo. + private static final byte[] LEADING_PAYLOAD = makeLeadingPayload(64 * 1024); + + private static byte[] makeLeadingPayload(int size) { + byte[] b = new byte[size]; + for (int i = 0; i < size; i++) { + b[i] = (byte) (i * 31 + 7); + } + return b; + } + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new EchoHttp2ClientHandler()); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + @Timeout(30) + void readsResponseWhileRequestBodyIsStillOpen() throws Exception { + var releaseRequest = new CountDownLatch(1); + var body = DataStream.ofInputStream( + new BlockingInputStream(LEADING_PAYLOAD, releaseRequest), + "application/octet-stream"); + var request = TestUtils.request(HttpVersion.HTTP_2, uri(), body); + + try { + // With duplex, send() returns on the response HEADERS even though the request body is still + // blocked mid-stream. Without it, this call would never return and the test would hit @Timeout. + var response = client.send(request); + assertEquals(200, response.statusCode()); + + try (InputStream in = response.body().asInputStream()) { + // Read one full 16 KB frame of the echo while the request body is still blocked. Getting any + // response body before releasing the request proves the two directions interleave. (One + // frame, not the whole payload, since the body only flushes on a full frame buffer.) + int prefixLen = 16 * 1024; + byte[] leadingEcho = readN(in, prefixLen); + byte[] expectedPrefix = Arrays.copyOf(LEADING_PAYLOAD, prefixLen); + assertArrayEquals(expectedPrefix, leadingEcho, "leading echo read while request still open"); + + // Now let the request body finish; the server echoes the rest plus END_STREAM. Drain the + // rest and confirm the full leading payload round-tripped. + releaseRequest.countDown(); + byte[] rest = in.readAllBytes(); + byte[] full = new byte[leadingEcho.length + rest.length]; + System.arraycopy(leadingEcho, 0, full, 0, leadingEcho.length); + System.arraycopy(rest, 0, full, leadingEcho.length, rest.length); + assertArrayEquals(LEADING_PAYLOAD, full, "full echoed request body"); + } + } finally { + // Ensure the background request-writer VT is never left blocked, even if an assertion above fails. + releaseRequest.countDown(); + } + } + + private static byte[] readN(InputStream in, int n) throws IOException { + byte[] buf = new byte[n]; + int read = 0; + while (read < n) { + int r = in.read(buf, read, n - read); + if (r < 0) { + throw new AssertionError("response stream ended early: wanted " + n + " bytes, got " + read); + } + read += r; + } + return buf; + } + + /** + * Emits {@code leading} bytes, then blocks on {@code release} before returning EOF. Models a request + * whose producer is still working: the body is open and unfinished until the test releases it. + */ + private static final class BlockingInputStream extends InputStream { + private final byte[] leading; + private final CountDownLatch release; + private int pos; + private boolean released; + + BlockingInputStream(byte[] leading, CountDownLatch release) { + this.leading = leading; + this.release = release; + } + + @Override + public int read() throws IOException { + byte[] one = new byte[1]; + int n = read(one, 0, 1); + return n < 0 ? -1 : (one[0] & 0xFF); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (pos < leading.length) { + int n = Math.min(len, leading.length - pos); + System.arraycopy(leading, pos, b, off, n); + pos += n; + return n; + } + if (!released) { + try { + // Block indefinitely until the test releases the request, modelling an in-progress + // upload. Crucially there is no self-timeout: a non-duplex client that writes the body + // inline before reading the response would block here forever (the test thread that + // releases this never gets to run), so the test fails via @Timeout rather than passing + // slowly. That is what makes this a real duplex discriminator. + release.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("interrupted while blocked on request release", e); + } + released = true; + } + return -1; + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ConcurrentStreamsHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ConcurrentStreamsHttp2Test.java new file mode 100644 index 0000000000..7f8a1932f2 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ConcurrentStreamsHttp2Test.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.ConnectionTrackingHttp2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.TextResponseHttp2ClientHandler; + +/** + * Tests that multiple HTTP/2 streams are multiplexed on a single connection. + */ +public class ConcurrentStreamsHttp2Test extends BaseHttpClientIntegTest { + + private ConnectionTrackingHttp2ClientHandler trackingHandler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + trackingHandler = new ConnectionTrackingHttp2ClientHandler( + new TextResponseHttp2ClientHandler(RESPONSE_CONTENTS)); + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> trackingHandler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .maxConnectionsPerRoute(1); // Force all streams onto single connection + } + + @Test + void multipleConcurrentStreamsOnSameConnection() throws Exception { + int numRequests = 10; + var futures = new ArrayList>(); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + for (int i = 0; i < numRequests; i++) { + futures.add(CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_2, REQUEST_CONTENTS); + var response = client.send(request); + return readBody(response); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor)); + } + + for (var future : futures) { + assertEquals(RESPONSE_CONTENTS, future.join()); + } + } + + assertEquals(numRequests, trackingHandler.requestCount(), "Should have received all requests"); + assertEquals(1, trackingHandler.connectionCount(), "All streams should use single connection"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/FlowControlHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/FlowControlHttp2Test.java new file mode 100644 index 0000000000..f90eccd6c1 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/FlowControlHttp2Test.java @@ -0,0 +1,67 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.InputStream; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.LargeResponseHttp2ClientHandler; + +/** + * Tests HTTP/2 flow control with large response bodies and slow client reads. + */ +public class FlowControlHttp2Test extends BaseHttpClientIntegTest { + + private static final int RESPONSE_SIZE = 1024 * 1024; // 1MB + private static final int CHUNK_SIZE = 16384; // 16KB chunks + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new LargeResponseHttp2ClientHandler(RESPONSE_SIZE, CHUNK_SIZE)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void largeResponseBodyWithFlowControl() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + var response = client.send(request); + + // Read slowly with small buffer to exercise flow control + byte[] buffer = new byte[1024]; + int totalRead = 0; + int bytesRead; + + try (InputStream is = response.body().asInputStream()) { + while ((bytesRead = is.read(buffer)) != -1) { + // Verify data pattern + for (int i = 0; i < bytesRead; i++) { + byte expected = (byte) ((totalRead + i) & 0xFF); + assertEquals(expected, buffer[i], "Data mismatch at position " + (totalRead + i)); + } + totalRead += bytesRead; + + // Simulate slow client - delay every 64KB + if (totalRead % (64 * 1024) == 0) { + Thread.sleep(10); + } + } + } + + assertEquals(RESPONSE_SIZE, totalRead, "Should receive complete response body"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/GoawayHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/GoawayHttp2Test.java new file mode 100644 index 0000000000..e267c34469 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/GoawayHttp2Test.java @@ -0,0 +1,55 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.GoawayAfterFirstRequestHandler; + +/** + * Tests that GOAWAY is handled gracefully - subsequent requests use new connection. + */ +public class GoawayHttp2Test extends BaseHttpClientIntegTest { + + private GoawayAfterFirstRequestHandler handler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + handler = new GoawayAfterFirstRequestHandler(RESPONSE_CONTENTS); + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> handler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void handlesGoawayGracefully() throws Exception { + // First request - server will send GOAWAY after response + var request1 = plainTextRequest(HttpVersion.HTTP_2, ""); + var response1 = client.send(request1); + assertEquals(RESPONSE_CONTENTS, readBody(response1)); + + // Wait for GOAWAY to be processed + Thread.sleep(200); + + // Second request - should use new connection due to GOAWAY + var request2 = plainTextRequest(HttpVersion.HTTP_2, ""); + var response2 = client.send(request2); + assertEquals(RESPONSE_CONTENTS, readBody(response2)); + + assertEquals(2, handler.connectionCount(), "Should use new connection after GOAWAY"); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/HighConcurrencyHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/HighConcurrencyHttp2Test.java new file mode 100644 index 0000000000..66c48e0dc6 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/HighConcurrencyHttp2Test.java @@ -0,0 +1,91 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.TextResponseHttp2ClientHandler; + +/** + * Stress test with many concurrent HTTP/2 requests. + * Tests various pool sizes to verify stream multiplexing and connection reuse. + */ +public class HighConcurrencyHttp2Test extends BaseHttpClientIntegTest { + + private int poolSize = 5; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new TextResponseHttp2ClientHandler(RESPONSE_CONTENTS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .maxConnectionsPerRoute(poolSize) + .maxTotalConnections(poolSize); + } + + static Stream poolConfigurations() { + return Stream.of( + // poolSize, numRequests - H2 multiplexes so fewer connections needed + Arguments.of(1, 50), // All on single connection + Arguments.of(2, 100), // 50 streams per connection + Arguments.of(5, 100), // 20 streams per connection + Arguments.of(10, 200) // 20 streams per connection + ); + } + + @ParameterizedTest(name = "pool={0}, requests={1}") + @MethodSource("poolConfigurations") + void handlesHighConcurrency(int poolSize, int numRequests) throws Exception { + this.poolSize = poolSize; + if (client != null) + client.close(); + setUp(); + + var futures = new ArrayList>(); + var successCount = new AtomicInteger(); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + for (int i = 0; i < numRequests; i++) { + futures.add(CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + var response = client.send(request); + var body = readBody(response); + successCount.incrementAndGet(); + return body; + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor)); + } + + for (var future : futures) { + assertEquals(RESPONSE_CONTENTS, future.join()); + } + } + + assertEquals(numRequests, successCount.get()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/MaxConcurrentStreamsHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/MaxConcurrentStreamsHttp2Test.java new file mode 100644 index 0000000000..c3e35dde62 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/MaxConcurrentStreamsHttp2Test.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.DelayedResponseHttp2ClientHandler; + +/** + * Tests HTTP/2 concurrent streams behavior. + */ +public class MaxConcurrentStreamsHttp2Test extends BaseHttpClientIntegTest { + + private DelayedResponseHttp2ClientHandler handler; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + handler = new DelayedResponseHttp2ClientHandler(RESPONSE_CONTENTS, 100); + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> handler); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .maxConnectionsPerRoute(1); // Force single connection + } + + @Test + void manyConcurrentStreamsOnSingleConnection() throws Exception { + int numRequests = 50; + var futures = new ArrayList>(); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + for (int i = 0; i < numRequests; i++) { + futures.add(CompletableFuture.supplyAsync(() -> { + try { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + var response = client.send(request); + return readBody(response); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executor)); + } + + for (var future : futures) { + assertEquals(RESPONSE_CONTENTS, future.join()); + } + } + + // Verify we actually had concurrent streams (not serialized) + assertTrue(handler.maxObservedConcurrent() > 1, + "Should have multiple concurrent streams, observed: " + handler.maxObservedConcurrent()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/PerMessageFlushHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/PerMessageFlushHttp2Test.java new file mode 100644 index 0000000000..3bf154c2cd --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/PerMessageFlushHttp2Test.java @@ -0,0 +1,213 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.EchoHttp2ClientHandler; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Proves per-message flushing of a streaming request body over HTTP/2: each small message is sent as its + * own DATA frame, not held in the output buffer until it fills or the stream closes. This is what lets a + * send-then-await-reply event protocol work without deadlocking. + * + *

The request body ({@link PingPongDataStream}) writes one message, then blocks until the test has read + * that message's echo, before writing the next. The server ({@link EchoHttp2ClientHandler}) echoes each + * request DATA frame into the response. The body writes via {@link DataStream#writeTo} and flushes after + * each message, like the event stream writer's DataStream. + * + *

Verified discriminator: on a coalescing path (transferTo, no per-message flush) message 0 never + * reaches the server, so its echo never arrives, the body never unblocks, and the test times out. + */ +public class PerMessageFlushHttp2Test extends BaseHttpClientIntegTest { + + private static final List MESSAGES = List.of("syn", "msg-1", "msg-2", "fin"); + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new EchoHttp2ClientHandler()); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + @Timeout(30) + void sendsEachMessageAsItsOwnFrameAndAwaitsEcho() throws Exception { + // Hands each message's echo (read from the response) back to the body so it can proceed. A + // non-blocking handoff (not SynchronousQueue) so the reader never blocks waiting for the writer + // to be poised at its poll(). + var echoes = new LinkedBlockingQueue(); + var body = new PingPongDataStream(MESSAGES, echoes); + + var request = TestUtils.request(HttpVersion.HTTP_2, uri(), body); + + try { + var response = client.send(request); + assertEquals(200, response.statusCode()); + + try (InputStream in = response.body().asInputStream()) { + var roundTripped = new StringBuilder(); + for (String message : MESSAGES) { + byte[] expected = message.getBytes(StandardCharsets.UTF_8); + byte[] echo = readN(in, expected.length); + assertArrayEquals(expected, echo, "echo of " + message); + roundTripped.append(new String(echo, StandardCharsets.UTF_8)); + // Release the body to write the next message only now that this one's echo is in hand. + echoes.add(echo); + } + assertEquals(-1, in.read(), "expected end of response after final message"); + assertEquals(String.join("", MESSAGES), roundTripped.toString()); + } + } finally { + body.unblock(); + } + } + + private static byte[] readN(InputStream in, int n) throws IOException { + byte[] buf = new byte[n]; + int read = 0; + while (read < n) { + int r = in.read(buf, read, n - read); + if (r < 0) { + throw new AssertionError("response ended early: wanted " + n + " bytes, got " + read); + } + read += r; + } + return buf; + } + + /** + * A request body that writes one message, flushes it, then blocks until the test has read that + * message's echo, modelling a send-then-await-reply event protocol. + */ + private static final class PingPongDataStream implements DataStream { + private final List messages; + private final LinkedBlockingQueue echoes; + private volatile boolean unblocked; + + PingPongDataStream(List messages, LinkedBlockingQueue echoes) { + this.messages = messages; + this.echoes = echoes; + } + + void unblock() { + unblocked = true; + } + + // Blocks until this message's echo has been read by the test, so the producer cannot run ahead of + // the response. Returns false if the test is tearing down. + private boolean awaitEcho(int messageIndex) throws IOException { + if (messageIndex + 1 >= messages.size()) { + return true; // last message: nothing to wait for + } + try { + while (echoes.poll(1, TimeUnit.SECONDS) == null) { + if (unblocked) { + return false; + } + } + return true; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("interrupted awaiting echo", e); + } + } + + @Override + public void writeTo(OutputStream out) throws IOException { + for (int i = 0; i < messages.size(); i++) { + out.write(messages.get(i).getBytes(StandardCharsets.UTF_8)); + out.flush(); // one message == one DATA frame + if (!awaitEcho(i)) { + return; + } + } + } + + // A real InputStream view with the same ping-pong gating, so on a coalescing transport + // (transferTo) the test deadlocks for real rather than failing on a stubbed-out method. + @Override + public InputStream asInputStream() { + return new InputStream() { + private int index; + private byte[] currentBytes; + private int currentPos; + + @Override + public int read() throws IOException { + byte[] one = new byte[1]; + int n = read(one, 0, 1); + return n < 0 ? -1 : (one[0] & 0xFF); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (currentBytes == null) { + if (index >= messages.size()) { + return -1; + } + // Gate on the previous message's echo before surfacing the next message's bytes. + if (index > 0 && !awaitEcho(index - 1)) { + return -1; + } + currentBytes = messages.get(index).getBytes(StandardCharsets.UTF_8); + currentPos = 0; + index++; + } + int n = Math.min(len, currentBytes.length - currentPos); + System.arraycopy(currentBytes, currentPos, b, off, n); + currentPos += n; + if (currentPos == currentBytes.length) { + currentBytes = null; + } + return n; + } + }; + } + + @Override + public long contentLength() { + return -1; + } + + @Override + public String contentType() { + return "application/octet-stream"; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return true; + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ResponseChannelHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ResponseChannelHttp2Test.java new file mode 100644 index 0000000000..19eff75943 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ResponseChannelHttp2Test.java @@ -0,0 +1,243 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.TestUtils; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.Http2ClientHandler; + +/** + * Tests the native channel response body path over a real HTTP/2 connection. + */ +public class ResponseChannelHttp2Test extends BaseHttpClientIntegTest { + + private static final int LARGE_RESPONSE_SIZE = 1024 * 1024; + private static final int CHUNK_SIZE = 16 * 1024; + private static final String SMALL_RESPONSE = "small response"; + private static final String PADDED_RESPONSE = "padded response"; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new PathResponseHandler()); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .maxConnectionsPerRoute(1); + } + + @Test + void readsLargeResponseThroughChannel() throws Exception { + var response = client.send(request("/large")); + var actual = new ByteArrayOutputStream(LARGE_RESPONSE_SIZE); + var buffer = ByteBuffer.allocate(8192); + + try (var channel = response.body().asChannel()) { + while (channel.read(buffer) != -1) { + buffer.flip(); + while (buffer.hasRemaining()) { + actual.write(buffer.get()); + } + buffer.clear(); + } + } + + assertArrayEquals(expectedLargeResponse(), actual.toByteArray()); + } + + @Test + void partialChannelReadCloseAllowsNextStreamOnSameConnection() throws Exception { + var largeResponse = client.send(request("/streaming-large")); + var buffer = ByteBuffer.allocate(8192); + + try (var channel = largeResponse.body().asChannel()) { + int totalRead = 0; + while (totalRead < buffer.capacity()) { + int read = channel.read(buffer); + if (read == -1) { + break; + } + totalRead += read; + } + assertEquals(buffer.capacity(), totalRead); + } + + var smallResponse = client.send(request("/small")); + assertEquals(SMALL_RESPONSE, readBody(smallResponse)); + } + + @Test + void slowChannelConsumerAllowsAnotherStreamToCompleteOnSameConnection() throws Exception { + var largeResponse = client.send(request("/large")); + var firstRead = new CountDownLatch(1); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + var largeBody = executor.submit(() -> { + var actual = new ByteArrayOutputStream(LARGE_RESPONSE_SIZE); + var buffer = ByteBuffer.allocate(1024); + try (var channel = largeResponse.body().asChannel()) { + while (channel.read(buffer) != -1) { + buffer.flip(); + while (buffer.hasRemaining()) { + actual.write(buffer.get()); + } + buffer.clear(); + firstRead.countDown(); + Thread.sleep(1); + } + } + return actual.toByteArray(); + }); + + assertTrue(firstRead.await(5, TimeUnit.SECONDS), "large response should start reading"); + + var smallResponse = client.send(request("/small")); + assertEquals(SMALL_RESPONSE, readBody(smallResponse)); + assertArrayEquals(expectedLargeResponse(), largeBody.get(10, TimeUnit.SECONDS)); + } + } + + @Test + void readsPaddedDataFrameAndKeepsConnectionUsable() throws Exception { + var paddedResponse = client.send(request("/padded")); + assertEquals(PADDED_RESPONSE, readBody(paddedResponse)); + + var smallResponse = client.send(request("/small")); + assertEquals(SMALL_RESPONSE, readBody(smallResponse)); + } + + private HttpRequest request(String path) { + return TestUtils.plainTextRequest(HttpVersion.HTTP_2, uri(path), ""); + } + + private static byte[] expectedLargeResponse() { + byte[] expected = new byte[LARGE_RESPONSE_SIZE]; + for (int i = 0; i < expected.length; i++) { + expected[i] = (byte) (i & 0xFF); + } + return expected; + } + + private static final class PathResponseHandler implements Http2ClientHandler { + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + String path = frame.headers().path().toString(); + if ("/small".equals(path)) { + sendSmallResponse(ctx); + } else if ("/padded".equals(path)) { + sendPaddedResponse(ctx); + } else if ("/streaming-large".equals(path)) { + sendStreamingLargeResponse(ctx); + } else { + sendLargeResponse(ctx); + } + } + + private static void sendSmallResponse(ChannelHandlerContext ctx) { + byte[] body = SMALL_RESPONSE.getBytes(StandardCharsets.UTF_8); + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "text/plain"); + headers.setInt("content-length", body.length); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(body), true)); + } + + private static void sendPaddedResponse(ChannelHandlerContext ctx) { + byte[] body = PADDED_RESPONSE.getBytes(StandardCharsets.UTF_8); + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "text/plain"); + headers.setInt("content-length", body.length); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(body), true, 10)); + } + + private static void sendLargeResponse(ChannelHandlerContext ctx) { + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "application/octet-stream"); + headers.setInt("content-length", LARGE_RESPONSE_SIZE); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + + int position = 0; + while (position < LARGE_RESPONSE_SIZE) { + int size = Math.min(CHUNK_SIZE, LARGE_RESPONSE_SIZE - position); + byte[] chunk = new byte[size]; + for (int i = 0; i < size; i++) { + chunk[i] = (byte) ((position + i) & 0xFF); + } + position += size; + ctx.write(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(chunk), + position == LARGE_RESPONSE_SIZE)); + } + ctx.flush(); + } + + private static void sendStreamingLargeResponse(ChannelHandlerContext ctx) { + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "application/octet-stream"); + headers.setInt("content-length", LARGE_RESPONSE_SIZE); + ctx.writeAndFlush(new DefaultHttp2HeadersFrame(headers)) + .addListener(future -> { + if (future.isSuccess()) { + writeStreamingChunk(ctx, 0); + } + }); + } + + private static void writeStreamingChunk(ChannelHandlerContext ctx, int position) { + if (position >= LARGE_RESPONSE_SIZE || !ctx.channel().isActive()) { + return; + } + + int size = Math.min(CHUNK_SIZE, LARGE_RESPONSE_SIZE - position); + byte[] chunk = new byte[size]; + for (int i = 0; i < size; i++) { + chunk[i] = (byte) ((position + i) & 0xFF); + } + + int nextPosition = position + size; + ctx.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(chunk), + nextPosition == LARGE_RESPONSE_SIZE)) + .addListener(future -> { + if (future.isSuccess()) { + ctx.executor().execute(() -> writeStreamingChunk(ctx, nextPosition)); + } + }); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/RstStreamHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/RstStreamHttp2Test.java new file mode 100644 index 0000000000..4071f8c708 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/RstStreamHttp2Test.java @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import io.netty.handler.codec.http2.Http2Error; +import java.io.IOException; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.RstStreamHttp2ClientHandler; + +/** + * Tests that RST_STREAM is handled correctly. + */ +public class RstStreamHttp2Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new RstStreamHttp2ClientHandler(Http2Error.CANCEL)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void handlesRstStreamError() { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + + assertThrows(IOException.class, () -> client.send(request)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ServerCloseMidStreamHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ServerCloseMidStreamHttp2Test.java new file mode 100644 index 0000000000..0d1a8e1ce5 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/ServerCloseMidStreamHttp2Test.java @@ -0,0 +1,46 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.PartialResponseHttp2ClientHandler; + +/** + * Tests that server closing connection mid-response throws IOException. + */ +public class ServerCloseMidStreamHttp2Test extends BaseHttpClientIntegTest { + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new PartialResponseHttp2ClientHandler()); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void handlesServerClosingConnectionMidResponse() { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + + assertThrows(IOException.class, () -> { + var response = client.send(request); + // Try to read full body - should fail since server closed mid-stream + response.body().asInputStream().readAllBytes(); + }); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/StreamingResponseHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/StreamingResponseHttp2Test.java new file mode 100644 index 0000000000..690e191c0a --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/StreamingResponseHttp2Test.java @@ -0,0 +1,67 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.StreamingResponseHttp2ClientHandler; + +/** + * Tests incremental reading of streaming response. + */ +public class StreamingResponseHttp2Test extends BaseHttpClientIntegTest { + + private static final List CHUNKS = List.of("chunk1-", "chunk2-", "chunk3-", "chunk4-", "chunk5"); + private static final long DELAY_MS = 50; + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new StreamingResponseHttp2ClientHandler(CHUNKS, DELAY_MS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void canReadStreamingResponseIncrementally() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + var response = client.send(request); + + var receivedChunks = new ArrayList(); + byte[] buffer = new byte[64]; + int bytesRead; + + try (InputStream is = response.body().asInputStream()) { + StringBuilder current = new StringBuilder(); + while ((bytesRead = is.read(buffer)) != -1) { + current.append(new String(buffer, 0, bytesRead)); + while (current.indexOf("-") >= 0) { + int idx = current.indexOf("-"); + receivedChunks.add(current.substring(0, idx + 1)); + current.delete(0, idx + 1); + } + } + if (!current.isEmpty()) { + receivedChunks.add(current.toString()); + } + } + + assertEquals(String.join("", CHUNKS), String.join("", receivedChunks)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/TrailerHeadersHttp2Test.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/TrailerHeadersHttp2Test.java new file mode 100644 index 0000000000..454321735d --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/h2/TrailerHeadersHttp2Test.java @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.api.TrailerSupport; +import software.amazon.smithy.java.http.client.HttpClient; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.it.server.NettyTestServer; +import software.amazon.smithy.java.http.client.it.server.h2.TrailerResponseHttp2ClientHandler; + +/** + * Tests HTTP/2 response with trailer headers. + */ +public class TrailerHeadersHttp2Test extends BaseHttpClientIntegTest { + + private static final Map TRAILERS = Map.of( + "x-checksum", + "abc123", + "x-request-id", + "req-456"); + + @Override + protected NettyTestServer.Builder configureServer(NettyTestServer.Builder builder) { + return builder + .httpVersion(HttpVersion.HTTP_2) + .h2ConnectionMode(NettyTestServer.H2ConnectionMode.PRIOR_KNOWLEDGE) + .http2HandlerFactory(ctx -> new TrailerResponseHttp2ClientHandler(RESPONSE_CONTENTS, TRAILERS)); + } + + @Override + protected HttpClient.Builder configureClient(HttpClient.Builder builder) { + return builder.httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE); + } + + @Test + void readsResponseWithTrailers() throws Exception { + var request = plainTextRequest(HttpVersion.HTTP_2, ""); + try (var response = client.send(request)) { + var body = response.body(); + var content = new String(body.asInputStream().readAllBytes()); + assertEquals(RESPONSE_CONTENTS, content); + + if (body instanceof TrailerSupport ts) { + var trailers = ts.trailerHeaders(); + assertNotNull(trailers, "Should have trailer headers"); + assertEquals("abc123", trailers.firstValue("x-checksum")); + assertEquals("req-456", trailers.firstValue("x-request-id")); + } else { + fail("Response body should implement TrailerSupport"); + } + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestLogger.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestLogger.java new file mode 100644 index 0000000000..963fac9270 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestLogger.java @@ -0,0 +1,497 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server; + +import io.netty.channel.Channel; +import software.amazon.smithy.java.logging.InternalLogger; + +public class NettyTestLogger { + + private final InternalLogger logger; + + protected NettyTestLogger(InternalLogger logger) { + this.logger = logger; + } + + /** + * Creates a new Netty logger. + * + * @param clazz The class that creates the logs + * @return The Netty logger + */ + public static NettyTestLogger getLogger(Class clazz) { + return new NettyTestLogger(InternalLogger.getLogger(clazz)); + } + + /** + * Logs a message for the given channel with the TRACE level. + *

+ * ` * @param channel channel + * + * @param message message + */ + public void trace(Channel channel, String message) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel)); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param throwable throwable + */ + public void trace(Channel channel, String message, Throwable throwable) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), throwable); + } + } + + /** + * Logs a message for the given channel with the TRACE level. + * Logs a message for the given channel with the TRACE level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + */ + public void trace(Channel channel, String message, Object p0) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), p0); + } + } + + /** + * Logs a message for the given channel with the TRACE level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + */ + public void trace(Channel channel, String message, Object p0, Object p1) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), p0, p1); + } + } + + /** + * Logs a message for the given channel with the TRACE level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + */ + public void trace(Channel channel, String message, Object p0, Object p1, Object p2) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), p0, p1, p2); + } + } + + /** + * Logs a message for the given channel with the TRACE level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + * @param p3 param three + */ + public void trace(Channel channel, String message, Object p0, Object p1, Object p2, Object p3) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), p0, p1, p2, p3); + } + } + + /** + * Logs a message for the given channel with the TRACE level. + * + * @param channel channel + * @param message message format + * @param args format args + */ + public void trace(Channel channel, String message, Object... args) { + if (logger.isTraceEnabled()) { + logger.trace(addChannelIdToMessage(message, channel), args); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message + */ + public void debug(Channel channel, String message) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel)); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + */ + public void debug(Channel channel, String message, Object p0) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel), p0); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + */ + public void debug(Channel channel, String message, Object p0, Object p1) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel), p0, p1); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + */ + public void debug(Channel channel, String message, Object p0, Object p1, Object p2) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel), p0, p1, p2); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + * @param p3 param three + */ + public void debug(Channel channel, String message, Object p0, Object p1, Object p2, Object p3) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel), p0, p1, p2, p3); + } + } + + /** + * Logs a message for the given channel with the DEBUG level. + * + * @param channel channel + * @param message message format + * @param args format args + */ + public void debug(Channel channel, String message, Object... args) { + if (logger.isDebugEnabled()) { + logger.debug(addChannelIdToMessage(message, channel), args); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message + */ + public void info(Channel channel, String message) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel)); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param throwable throwable + */ + public void info(Channel channel, String message, Throwable throwable) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), throwable); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + */ + public void info(Channel channel, String message, Object p0) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), p0); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + */ + public void info(Channel channel, String message, Object p0, Object p1) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), p0, p1); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + */ + public void info(Channel channel, String message, Object p0, Object p1, Object p2) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), p0, p1, p2); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + * @param p3 param three + */ + public void info(Channel channel, String message, Object p0, Object p1, Object p2, Object p3) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), p0, p1, p2, p3); + } + } + + /** + * Logs a message for the given channel with the INFO level. + * + * @param channel channel + * @param message message format + * @param args format args + */ + public void info(Channel channel, String message, Object... args) { + if (logger.isInfoEnabled()) { + logger.info(addChannelIdToMessage(message, channel), args); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message + */ + public void warn(Channel channel, String message) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel)); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + */ + public void warn(Channel channel, String message, Object p0) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), p0); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param throwable throwable + */ + public void warn(Channel channel, String message, Throwable throwable) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), throwable); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + */ + public void warn(Channel channel, String message, Object p0, Object p1) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), p0, p1); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + */ + public void warn(Channel channel, String message, Object p0, Object p1, Object p2) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), p0, p1, p2); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + * @param p3 param three + */ + public void warn(Channel channel, String message, Object p0, Object p1, Object p2, Object p3) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), p0, p1, p2, p3); + } + } + + /** + * Logs a message for the given channel with the WARN level. + * + * @param channel channel + * @param message message format + * @param args format args + */ + public void warn(Channel channel, String message, Object... args) { + if (logger.isWarnEnabled()) { + logger.warn(addChannelIdToMessage(message, channel), args); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message + */ + public void error(Channel channel, String message) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel)); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + */ + public void error(Channel channel, String message, Object p0) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel), p0); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + */ + public void error(Channel channel, String message, Object p0, Object p1) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel), p0, p1); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + */ + public void error(Channel channel, String message, Object p0, Object p1, Object p2) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel), p0, p1, p2); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message format + * @param p0 param zero + * @param p1 param one + * @param p2 param two + * @param p3 param three + */ + public void error(Channel channel, String message, Object p0, Object p1, Object p2, Object p3) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel), p0, p1, p2, p3); + } + } + + /** + * Logs a message for the given channel with the ERROR level. + * + * @param channel channel + * @param message message format + * @param args format args + */ + public void error(Channel channel, String message, Object... args) { + if (logger.isErrorEnabled()) { + logger.error(addChannelIdToMessage(message, channel), args); + } + } + + protected String addChannelIdToMessage(String message, Channel channel) { + if (channel == null) { + return message; + } + String id; + if (logger.isDebugEnabled()) { + id = channel.toString(); + } else { + id = channel.id().asShortText(); + } + return String.format("[Channel: %s] %s", id, message); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestServer.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestServer.java new file mode 100644 index 0000000000..98a5257a14 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/NettyTestServer.java @@ -0,0 +1,189 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.channel.nio.NioIoHandler; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.util.concurrent.DefaultThreadFactory; +import java.net.InetSocketAddress; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.it.server.h1.Http11ClientHandlerFactory; +import software.amazon.smithy.java.http.client.it.server.h2.Http2ClientHandlerFactory; + +/** + * Netty-based test server for HTTP client integration tests. + * + *

Supports HTTP/1.1 and HTTP/2 with optional TLS and ALPN negotiation. + */ +public class NettyTestServer { + private static final NettyTestLogger LOGGER = NettyTestLogger.getLogger(NettyTestServer.class); + private final EventLoopGroup bossGroup; + private final EventLoopGroup workerGroup; + private final Config config; + private int port; + private Channel channel; + + public NettyTestServer(Builder builder) { + this.port = builder.port; + this.config = builder.buildConfig(); + this.bossGroup = createEventLoopGroup(1); + this.workerGroup = createEventLoopGroup(4); + } + + public static Builder builder() { + return new Builder(); + } + + public void start() throws InterruptedException { + var http2 = config.httpVersion == HttpVersion.HTTP_2; + var bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ServerInitializer(config)); + + channel = bootstrap.bind("127.0.0.1", this.port).sync().channel(); + var address = (InetSocketAddress) channel.localAddress(); + this.port = address.getPort(); + LOGGER.info(null, "Server started on port {}, using: {}", port, (http2 ? " (HTTP/2)" : " (HTTP/1.1)")); + } + + public void stop() { + if (channel != null) { + channel.close().awaitUninterruptibly(); + } + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } + + public int getPort() { + return port; + } + + private EventLoopGroup createEventLoopGroup(Integer nThreads) { + var threadFactory = new DefaultThreadFactory("test-server", true); + if (nThreads != null) { + return new MultiThreadIoEventLoopGroup(nThreads, + threadFactory, + NioIoHandler.newFactory()); + + } + return new MultiThreadIoEventLoopGroup(threadFactory, + NioIoHandler.newFactory()); + } + + /** + * The connection mode for establishing HTTP/2 connections. + */ + public enum H2ConnectionMode { + /** + * Uses ALPN over https and prior knowledge over http. + */ + AUTO, + /** + * Negotiate using Application Layer Protocol Negotiation. This mode requires HTTPS. + */ + ALPN, + /** + * Use prior knowledge. + */ + PRIOR_KNOWLEDGE + } + + public static class Config { + private final int port; + private final HttpVersion httpVersion; + private final H2ConnectionMode h2ConnectionMode; + private final SslContextBuilder sslContextBuilder; + private final Http2ClientHandlerFactory http2HandlerFactory; + private final Http11ClientHandlerFactory http11HandlerFactory; + + public Config(Builder builder) { + this.h2ConnectionMode = builder.h2ConnectionMode; + this.sslContextBuilder = builder.sslContextBuilder; + this.httpVersion = builder.httpVersion; + this.port = builder.port; + this.http2HandlerFactory = builder.http2HandlerFactory; + this.http11HandlerFactory = builder.http11HandlerFactory; + } + + public int port() { + return this.port; + } + + public HttpVersion httpVersion() { + return this.httpVersion; + } + + public H2ConnectionMode h2ConnectionMode() { + return this.h2ConnectionMode; + } + + public SslContextBuilder sslContextBuilder() { + return this.sslContextBuilder; + } + + public Http2ClientHandlerFactory http2HandlerFactory() { + return http2HandlerFactory; + } + + public Http11ClientHandlerFactory http11HandlerFactory() { + return http11HandlerFactory; + } + } + + public static class Builder { + private int port = 0; + private HttpVersion httpVersion = HttpVersion.HTTP_1_1; + private H2ConnectionMode h2ConnectionMode = + H2ConnectionMode.AUTO; + private SslContextBuilder sslContextBuilder; + private Http2ClientHandlerFactory http2HandlerFactory; + private Http11ClientHandlerFactory http11HandlerFactory; + + public Builder port(int port) { + this.port = port; + return this; + } + + public Builder httpVersion(HttpVersion httpVersion) { + this.httpVersion = httpVersion; + return this; + } + + public Builder h2ConnectionMode(H2ConnectionMode h2ConnectionMode) { + this.h2ConnectionMode = h2ConnectionMode; + return this; + } + + public Builder sslContextBuilder(SslContextBuilder sslContextBuilder) { + this.sslContextBuilder = sslContextBuilder; + return this; + } + + public Builder http2HandlerFactory(Http2ClientHandlerFactory http2HandlerFactory) { + this.http2HandlerFactory = http2HandlerFactory; + return this; + } + + public Builder http11HandlerFactory(Http11ClientHandlerFactory http11HandlerFactory) { + this.http11HandlerFactory = http11HandlerFactory; + return this; + } + + public NettyTestServer build() { + return new NettyTestServer(this); + } + + public Config buildConfig() { + return new Config(this); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/ServerInitializer.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/ServerInitializer.java new file mode 100644 index 0000000000..4002d503c4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/ServerInitializer.java @@ -0,0 +1,131 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2MultiplexHandler; +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.ApplicationProtocolNames; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import javax.net.ssl.SSLException; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.it.server.h1.Http11ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h1.Http11ClientHandlerFactory; +import software.amazon.smithy.java.http.client.it.server.h1.Http11Handler; +import software.amazon.smithy.java.http.client.it.server.h2.Http2ClientHandler; +import software.amazon.smithy.java.http.client.it.server.h2.Http2ClientHandlerFactory; +import software.amazon.smithy.java.http.client.it.server.h2.Http2ConnectionFrameHandler; +import software.amazon.smithy.java.http.client.it.server.h2.Http2StreamFrameHandler; + +/** + * Netty channel initializer for the test server. + * + *

Configures the pipeline for HTTP/1.1 or HTTP/2 based on the server configuration, + * with optional TLS and ALPN support. + */ +public class ServerInitializer extends ChannelInitializer { + private final Http2ClientHandlers h2ClientHandlers; + private final Http11ClientHandlers h11ClientHandlers; + private final NettyTestServer.Config config; + + public ServerInitializer(NettyTestServer.Config config) { + this.config = config; + if (config.httpVersion() == HttpVersion.HTTP_2) { + var handlersFactory = Objects.requireNonNull(config.http2HandlerFactory()); + this.h2ClientHandlers = new Http2ClientHandlers(handlersFactory); + this.h11ClientHandlers = null; + } else { + var handlersFactory = Objects.requireNonNull(config.http11HandlerFactory()); + this.h11ClientHandlers = new Http11ClientHandlers(handlersFactory); + this.h2ClientHandlers = null; + } + } + + @Override + protected void initChannel(SocketChannel ch) { + var pipeline = ch.pipeline(); + var sslContextBuilder = config.sslContextBuilder(); + if (sslContextBuilder != null) { + try { + if (config.h2ConnectionMode() == NettyTestServer.H2ConnectionMode.ALPN) { + sslContextBuilder.applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2)); + } + pipeline.addLast(sslContextBuilder.build().newHandler(ch.alloc())); + } catch (SSLException e) { + throw new RuntimeException(e); + } + } + + if (config.httpVersion() == HttpVersion.HTTP_2) { + // HTTP/2 with prior knowledge + pipeline.addLast(Http2FrameCodecBuilder.forServer().build()); + pipeline.addLast(new Http2MultiplexHandler(new ChannelInitializer<>() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new Http2StreamFrameHandler(h2ClientHandlers)); + } + })); + // Handle connection-level frames (SETTINGS, PING, etc.) + pipeline.addLast(new Http2ConnectionFrameHandler()); + } else { + // HTTP/1.1 + pipeline.addLast(new HttpServerCodec()); + pipeline.addLast(new HttpObjectAggregator(1024 * 1024)); + pipeline.addLast(new Http11Handler(h11ClientHandlers)); + } + } + + public static final class Http2ClientHandlers { + private final Http2ClientHandlerFactory factory; + private final Map h2ClientHandlers = new ConcurrentHashMap<>(); + + Http2ClientHandlers(Http2ClientHandlerFactory factory) { + this.factory = factory; + } + + public Http2ClientHandler create(ChannelHandlerContext ctx) { + var result = factory.create(ctx); + h2ClientHandlers.put(ctx.channel().id(), result); + return result; + } + + public Http2ClientHandler get(ChannelHandlerContext ctx) { + return h2ClientHandlers.get(ctx.channel().id()); + } + } + + public static final class Http11ClientHandlers { + private final Http11ClientHandlerFactory factory; + private final Map h11ClientHandlers = new ConcurrentHashMap<>(); + + Http11ClientHandlers(Http11ClientHandlerFactory factory) { + this.factory = factory; + } + + public Http11ClientHandler create(ChannelHandlerContext ctx) { + var result = factory.create(ctx); + h11ClientHandlers.put(ctx.channel().id(), result); + return result; + } + + public Http11ClientHandler get(ChannelHandlerContext ctx) { + return h11ClientHandlers.get(ctx.channel().id()); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/TestCertificateGenerator.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/TestCertificateGenerator.java new file mode 100644 index 0000000000..ca146733b4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/TestCertificateGenerator.java @@ -0,0 +1,137 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Date; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +public class TestCertificateGenerator { + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + public static CertificateBundle generateCertificates() throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + + KeyPair caKeyPair = keyGen.generateKeyPair(); + X509Certificate caCert = generateCACertificate(caKeyPair); + + KeyPair serverKeyPair = keyGen.generateKeyPair(); + X509Certificate serverCert = generateServerCertificate(serverKeyPair, caKeyPair, caCert); + + return new CertificateBundle(caCert, serverCert, serverKeyPair.getPrivate()); + } + + private static X509Certificate generateCACertificate(KeyPair keyPair) throws Exception { + var issuer = new X500Name("CN=Test CA, O=Test, C=US"); + var serial = BigInteger.valueOf(System.currentTimeMillis()); + var notBefore = new Date(); + var notAfter = new Date(notBefore.getTime() + 365L * 24 * 60 * 60 * 1000); + + // Create extension utils for key identifiers + var extUtils = new JcaX509ExtensionUtils(); + var subjectKeyIdentifier = extUtils.createSubjectKeyIdentifier(keyPair.getPublic()); + + var certBuilder = new JcaX509v3CertificateBuilder( + issuer, + serial, + notBefore, + notAfter, + issuer, + keyPair.getPublic()) + .addExtension(Extension.basicConstraints, true, new BasicConstraints(true)) + .addExtension(Extension.keyUsage, + true, + new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign)) + .addExtension(Extension.subjectKeyIdentifier, false, subjectKeyIdentifier); + + var signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()); + var certHolder = certBuilder.build(signer); + + return new JcaX509CertificateConverter().getCertificate(certHolder); + } + + private static X509Certificate generateServerCertificate( + KeyPair serverKeyPair, + KeyPair caKeyPair, + X509Certificate caCert + ) throws Exception { + // Get the issuer directly from the CA cert to ensure exact match + var issuer = X500Name.getInstance(caCert.getSubjectX500Principal().getEncoded()); + var subject = new X500Name("CN=localhost, O=Test, C=US"); + var serial = BigInteger.valueOf(System.currentTimeMillis()); + var notBefore = new Date(); + var notAfter = new Date(notBefore.getTime() + 365L * 24 * 60 * 60 * 1000); + + var sanNames = new GeneralName[] { + new GeneralName(GeneralName.dNSName, "localhost"), + new GeneralName(GeneralName.iPAddress, "127.0.0.1") + }; + + // Create extension utils for key identifiers + var extUtils = new JcaX509ExtensionUtils(); + var subjectKeyIdentifier = extUtils.createSubjectKeyIdentifier(serverKeyPair.getPublic()); + var authorityKeyIdentifier = extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey()); + + var certBuilder = new JcaX509v3CertificateBuilder( + issuer, + serial, + notBefore, + notAfter, + subject, + serverKeyPair.getPublic()) + .addExtension(Extension.subjectAlternativeName, false, new GeneralNames(sanNames)) + .addExtension(Extension.keyUsage, + true, + new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment)) + .addExtension(Extension.extendedKeyUsage, + false, + new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth)) + .addExtension(Extension.subjectKeyIdentifier, false, subjectKeyIdentifier) + .addExtension(Extension.authorityKeyIdentifier, false, authorityKeyIdentifier); + + var signer = new JcaContentSignerBuilder("SHA256withRSA").build(caKeyPair.getPrivate()); + var certHolder = certBuilder.build(signer); + + return new JcaX509CertificateConverter().getCertificate(certHolder); + } + + public static class CertificateBundle { + public final X509Certificate caCertificate; + public final X509Certificate serverCertificate; + public final PrivateKey serverPrivateKey; + + public CertificateBundle( + X509Certificate caCertificate, + X509Certificate serverCertificate, + PrivateKey serverPrivateKey + ) { + this.caCertificate = caCertificate; + this.serverCertificate = serverCertificate; + this.serverPrivateKey = serverPrivateKey; + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ChunkedResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ChunkedResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..0047368bf2 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ChunkedResponseHttp11ClientHandler.java @@ -0,0 +1,44 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpContent; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.DefaultLastHttpContent; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * HTTP/1.1 handler that sends chunked transfer encoding response. + */ +public class ChunkedResponseHttp11ClientHandler implements Http11ClientHandler { + + private final List chunks; + + public ChunkedResponseHttp11ClientHandler(List chunks) { + this.chunks = chunks; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + var response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + ctx.write(response); + + for (String chunk : chunks) { + ctx.write(new DefaultHttpContent(Unpooled.wrappedBuffer(chunk.getBytes(StandardCharsets.UTF_8)))); + } + ctx.writeAndFlush(new DefaultLastHttpContent()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionCloseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionCloseHttp11ClientHandler.java new file mode 100644 index 0000000000..d5abb94932 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionCloseHttp11ClientHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; + +/** + * HTTP/1.1 handler that sends Connection: close header. + */ +public class ConnectionCloseHttp11ClientHandler implements Http11ClientHandler { + + private final String responseBody; + + public ConnectionCloseHttp11ClientHandler(String responseBody) { + this.responseBody = responseBody; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + byte[] body = responseBody.getBytes(StandardCharsets.UTF_8); + var response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.wrappedBuffer(body)); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, body.length); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + response.headers().set(HttpHeaderNames.CONNECTION, "close"); + ctx.writeAndFlush(response).addListener(f -> ctx.close()); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionTrackingHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionTrackingHttp11ClientHandler.java new file mode 100644 index 0000000000..9b11cffb9d --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ConnectionTrackingHttp11ClientHandler.java @@ -0,0 +1,67 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * HTTP/1.1 handler that tracks unique connections and request counts. + */ +public class ConnectionTrackingHttp11ClientHandler implements Http11ClientHandler { + + private final Http11ClientHandler delegate; + private final Set seenConnections = ConcurrentHashMap.newKeySet(); + private final AtomicInteger requestCount = new AtomicInteger(); + + public ConnectionTrackingHttp11ClientHandler(Http11ClientHandler delegate) { + this.delegate = delegate; + } + + public int connectionCount() { + return seenConnections.size(); + } + + public int requestCount() { + return requestCount.get(); + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + seenConnections.add(ctx.channel().id()); + requestCount.incrementAndGet(); + delegate.onFullRequest(ctx, request); + } + + @Override + public void onRequest(ChannelHandlerContext ctx, HttpRequest request) { + seenConnections.add(ctx.channel().id()); + requestCount.incrementAndGet(); + delegate.onRequest(ctx, request); + } + + @Override + public void onContent(ChannelHandlerContext ctx, HttpContent content) { + delegate.onContent(ctx, content); + } + + @Override + public void onLastContent(ChannelHandlerContext ctx, LastHttpContent content) { + delegate.onLastContent(ctx, content); + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + delegate.onException(ctx, cause); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ContinueHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ContinueHttp11ClientHandler.java new file mode 100644 index 0000000000..f97ca02457 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/ContinueHttp11ClientHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicReference; + +/** + * HTTP/1.1 handler that handles 100-continue correctly. + */ +public class ContinueHttp11ClientHandler implements Http11ClientHandler { + + private final String responseBody; + private final AtomicReference capturedBody = new AtomicReference<>(Unpooled.buffer()); + + public ContinueHttp11ClientHandler(String responseBody) { + this.responseBody = responseBody; + } + + public ByteBuf capturedBody() { + return capturedBody.get(); + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + // Check for Expect: 100-continue and send 100 Continue when seen + if (request.headers().contains(HttpHeaderNames.EXPECT, "100-continue", true)) { + ctx.writeAndFlush(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE)); + } + + // Capture request body + capturedBody.get().writeBytes(request.content()); + + // Send final response + byte[] body = responseBody.getBytes(StandardCharsets.UTF_8); + var response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.wrappedBuffer(body)); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, body.length); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + ctx.writeAndFlush(response); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/DelayedResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/DelayedResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..4500492313 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/DelayedResponseHttp11ClientHandler.java @@ -0,0 +1,52 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import java.util.concurrent.TimeUnit; + +/** + * HTTP/1.1 handler that delays response. + */ +public class DelayedResponseHttp11ClientHandler implements Http11ClientHandler { + + private final Http11ClientHandler delegate; + private final long delayMs; + + public DelayedResponseHttp11ClientHandler(Http11ClientHandler delegate, long delayMs) { + this.delegate = delegate; + this.delayMs = delayMs; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + ctx.executor().schedule(() -> delegate.onFullRequest(ctx, request), delayMs, TimeUnit.MILLISECONDS); + } + + @Override + public void onRequest(ChannelHandlerContext ctx, HttpRequest request) { + delegate.onRequest(ctx, request); + } + + @Override + public void onContent(ChannelHandlerContext ctx, HttpContent content) { + delegate.onContent(ctx, content); + } + + @Override + public void onLastContent(ChannelHandlerContext ctx, LastHttpContent content) { + delegate.onLastContent(ctx, content); + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + delegate.onException(ctx, cause); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/EmptyResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/EmptyResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..fa8f7d9694 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/EmptyResponseHttp11ClientHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +/** + * HTTP/1.1 handler that sends empty response body. + */ +public class EmptyResponseHttp11ClientHandler implements Http11ClientHandler { + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + var response = + new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT, Unpooled.EMPTY_BUFFER); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0); + ctx.writeAndFlush(response); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandler.java new file mode 100644 index 0000000000..dab893d0e4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; + +/** + * Handler interface for HTTP/1.1 requests in the test server. + */ +public interface Http11ClientHandler { + + /** + * Called when a complete HTTP request is received (headers + body aggregated). + * + * @param ctx the channel handler context + * @param request the complete HTTP request + */ + default void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) {} + + /** + * Called when HTTP request headers are received (streaming mode). + * + * @param ctx the channel handler context + * @param request the HTTP request headers + */ + default void onRequest(ChannelHandlerContext ctx, HttpRequest request) {} + + /** + * Called when HTTP request body content is received (streaming mode). + * + * @param ctx the channel handler context + * @param content the HTTP content chunk + */ + default void onContent(ChannelHandlerContext ctx, HttpContent content) {} + + /** + * Called when the last HTTP request body content is received (streaming mode). + * + * @param ctx the channel handler context + * @param content the last HTTP content chunk + */ + default void onLastContent(ChannelHandlerContext ctx, LastHttpContent content) {} + + /** + * Called when an exception occurs during request processing. + * + * @param ctx the channel handler context + * @param cause the exception + */ + default void onException(ChannelHandlerContext ctx, Throwable cause) { + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandlerFactory.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandlerFactory.java new file mode 100644 index 0000000000..f457221747 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11ClientHandlerFactory.java @@ -0,0 +1,13 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; + +@FunctionalInterface +public interface Http11ClientHandlerFactory { + Http11ClientHandler create(ChannelHandlerContext ctx); +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11Handler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11Handler.java new file mode 100644 index 0000000000..fa9436af50 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/Http11Handler.java @@ -0,0 +1,54 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import software.amazon.smithy.java.http.client.it.server.ServerInitializer; + +public class Http11Handler extends ChannelInboundHandlerAdapter { + private final ServerInitializer.Http11ClientHandlers handlers; + + public Http11Handler(ServerInitializer.Http11ClientHandlers handlers) { + this.handlers = handlers; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof HttpRequest httpRequest) { + var handler = handlers.create(ctx); + // Initial request line and headers + if (httpRequest instanceof FullHttpRequest fullHttpRequest) { + handler.onFullRequest(ctx, fullHttpRequest); + } else { + handler.onRequest(ctx, httpRequest); + } + } else if (msg instanceof HttpContent httpContent) { + var handler = handlers.get(ctx); + if (httpContent instanceof LastHttpContent httpLastContent) { + handler.onLastContent(ctx, httpLastContent); + } else { + handler.onContent(ctx, httpContent); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + var handler = handlers.get(ctx); + handler.onException(ctx, cause); + ctx.close(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + ctx.fireChannelInactive(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/LargeHeadersHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/LargeHeadersHttp11ClientHandler.java new file mode 100644 index 0000000000..d5a3f4e066 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/LargeHeadersHttp11ClientHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; + +/** + * HTTP/1.1 handler that sends response with large headers. + */ +public class LargeHeadersHttp11ClientHandler implements Http11ClientHandler { + + private final String body; + private final int headerCount; + private final int headerValueSize; + + public LargeHeadersHttp11ClientHandler(String body, int headerCount, int headerValueSize) { + this.body = body; + this.headerCount = headerCount; + this.headerValueSize = headerValueSize; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8); + var response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.wrappedBuffer(bodyBytes)); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, bodyBytes.length); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + + // Add large headers + String largeValue = "x".repeat(headerValueSize); + for (int i = 0; i < headerCount; i++) { + response.headers().set("x-large-header-" + i, largeValue); + } + + ctx.writeAndFlush(response); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/MultiplexingHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/MultiplexingHttp11ClientHandler.java new file mode 100644 index 0000000000..bb0744cdad --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/MultiplexingHttp11ClientHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import java.util.Arrays; +import java.util.List; + +public class MultiplexingHttp11ClientHandler implements Http11ClientHandler { + private final List handlers; + + public MultiplexingHttp11ClientHandler(Http11ClientHandler... handlers) { + this.handlers = Arrays.asList(handlers); + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + for (var handler : handlers) { + handler.onFullRequest(ctx, request); + } + } + + @Override + public void onRequest(ChannelHandlerContext ctx, HttpRequest request) { + for (var handler : handlers) { + handler.onRequest(ctx, request); + } + } + + @Override + public void onContent(ChannelHandlerContext ctx, HttpContent content) { + for (var handler : handlers) { + handler.onContent(ctx, content); + } + } + + @Override + public void onLastContent(ChannelHandlerContext ctx, LastHttpContent content) { + for (var handler : handlers) { + handler.onLastContent(ctx, content); + } + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + for (var handler : handlers) { + handler.onException(ctx, cause); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/PartialResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/PartialResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..ffc304d9b4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/PartialResponseHttp11ClientHandler.java @@ -0,0 +1,44 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpContent; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; + +/** + * Handler that sends partial response then closes connection. + * Used to test client handling of server closing mid-response. + */ +public class PartialResponseHttp11ClientHandler implements Http11ClientHandler { + private final String partialBody; + private final int advertisedLength; + + public PartialResponseHttp11ClientHandler(String partialBody, int advertisedLength) { + this.partialBody = partialBody; + this.advertisedLength = advertisedLength; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + var response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + response.headers().set("content-length", advertisedLength); + response.headers().set("content-type", "text/plain"); + ctx.write(response); + + // Send partial body (less than advertised) + ctx.write(new DefaultHttpContent(Unpooled.copiedBuffer(partialBody, StandardCharsets.UTF_8))); + ctx.flush(); + + // Close connection without sending full body + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/RequestCapturingHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/RequestCapturingHttp11ClientHandler.java new file mode 100644 index 0000000000..6705e1cb65 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/RequestCapturingHttp11ClientHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RequestCapturingHttp11ClientHandler implements Http11ClientHandler { + private final Map> capturedHeaders = new HashMap<>(); + private final ByteArrayOutputStream capturedBody = new ByteArrayOutputStream(); + private Throwable cause; + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + captureHeaders(request); + captureBody(request.content()); + } + + @Override + public void onRequest(ChannelHandlerContext ctx, HttpRequest request) { + captureHeaders(request); + } + + @Override + public void onContent(ChannelHandlerContext ctx, HttpContent content) { + captureBody(content.content()); + } + + @Override + public void onLastContent(ChannelHandlerContext ctx, LastHttpContent content) { + captureBody(content.content()); + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + this.cause = cause; + } + + private void captureHeaders(HttpRequest request) { + var headers = request.headers(); + for (var kvp : headers) { + capturedHeaders.computeIfAbsent(kvp.getKey(), k -> new ArrayList<>()).add(kvp.getValue()); + } + } + + private void captureBody(ByteBuf content) { + var bytes = new byte[content.readableBytes()]; + content.getBytes(content.readerIndex(), bytes); // Don't consume the buffer + try { + capturedBody.write(bytes); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Throwable cause() { + return cause; + } + + public Map> capturedHeaders() { + return capturedHeaders; + } + + public ByteArrayOutputStream capturedBody() { + return capturedBody; + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/StatusCodeHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/StatusCodeHttp11ClientHandler.java new file mode 100644 index 0000000000..ac7f3b29c3 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/StatusCodeHttp11ClientHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +/** + * HTTP/1.1 handler that sends configurable status code. + */ +public class StatusCodeHttp11ClientHandler implements Http11ClientHandler { + + private final int statusCode; + + public StatusCodeHttp11ClientHandler(int statusCode) { + this.statusCode = statusCode; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + var status = HttpResponseStatus.valueOf(statusCode); + var response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.EMPTY_BUFFER); + + // Some status codes must not have body + if (statusCode != 204 && statusCode != 304) { + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0); + } + + ctx.writeAndFlush(response); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TextResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TextResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..f2e40651f4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TextResponseHttp11ClientHandler.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.util.CharsetUtil; + +/** + * HTTP/1.1 handler that sends a simple text response. + */ +public class TextResponseHttp11ClientHandler implements Http11ClientHandler { + private final String message; + + public TextResponseHttp11ClientHandler(String message) { + this.message = message; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + sendResponse(ctx); + } + + @Override + public void onRequest(ChannelHandlerContext ctx, HttpRequest request) { + sendResponse(ctx); + } + + private void sendResponse(ChannelHandlerContext ctx) { + var content = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8); + var response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + content); + var headers = response.headers(); + headers.set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + headers.set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); + headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + ctx.writeAndFlush(response); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TrailerResponseHttp11ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TrailerResponseHttp11ClientHandler.java new file mode 100644 index 0000000000..0ca7356892 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h1/TrailerResponseHttp11ClientHandler.java @@ -0,0 +1,52 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h1; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpContent; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.DefaultLastHttpContent; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +/** + * HTTP/1.1 handler that sends chunked response with trailers. + */ +public class TrailerResponseHttp11ClientHandler implements Http11ClientHandler { + + private final String body; + private final Map trailers; + + public TrailerResponseHttp11ClientHandler(String body, Map trailers) { + this.body = body; + this.trailers = trailers; + } + + @Override + public void onFullRequest(ChannelHandlerContext ctx, FullHttpRequest request) { + var response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); + response.headers().set("trailer", String.join(", ", trailers.keySet())); + ctx.write(response); + + // Send body chunk + ctx.write(new DefaultHttpContent(Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8)))); + + // Send last chunk with trailers + var lastContent = new DefaultLastHttpContent(); + for (var entry : trailers.entrySet()) { + lastContent.trailingHeaders().set(entry.getKey(), entry.getValue()); + } + ctx.writeAndFlush(lastContent); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/ConnectionTrackingHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/ConnectionTrackingHttp2ClientHandler.java new file mode 100644 index 0000000000..18910fa00e --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/ConnectionTrackingHttp2ClientHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * HTTP/2 handler that tracks unique connections and request counts. + */ +public class ConnectionTrackingHttp2ClientHandler implements Http2ClientHandler { + + private final Http2ClientHandler delegate; + private final Set seenConnections = ConcurrentHashMap.newKeySet(); + private final AtomicInteger requestCount = new AtomicInteger(); + + public ConnectionTrackingHttp2ClientHandler(Http2ClientHandler delegate) { + this.delegate = delegate; + } + + public int connectionCount() { + return seenConnections.size(); + } + + public int requestCount() { + return requestCount.get(); + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + // parent() gives us the connection channel (stream channels have the connection as parent) + seenConnections.add(ctx.channel().parent().id()); + requestCount.incrementAndGet(); + delegate.onHeadersFrame(ctx, frame); + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + delegate.onDataFrame(ctx, frame); + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + delegate.onException(ctx, cause); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/DelayedResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/DelayedResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..caea26b85e --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/DelayedResponseHttp2ClientHandler.java @@ -0,0 +1,58 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * HTTP/2 handler that delays response and tracks concurrent streams. + */ +public class DelayedResponseHttp2ClientHandler implements Http2ClientHandler { + + private final String responseBody; + private final long delayMs; + private final AtomicInteger concurrentStreams = new AtomicInteger(); + private volatile int maxObservedConcurrent = 0; + + public DelayedResponseHttp2ClientHandler(String responseBody, long delayMs) { + this.responseBody = responseBody; + this.delayMs = delayMs; + } + + public int maxObservedConcurrent() { + return maxObservedConcurrent; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + int current = concurrentStreams.incrementAndGet(); + synchronized (this) { + if (current > maxObservedConcurrent) { + maxObservedConcurrent = current; + } + } + + ctx.executor().schedule(() -> { + concurrentStreams.decrementAndGet(); + + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "text/plain"); + byte[] body = responseBody.getBytes(StandardCharsets.UTF_8); + headers.setInt("content-length", body.length); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(body), true)); + }, delayMs, TimeUnit.MILLISECONDS); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/EchoHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/EchoHttp2ClientHandler.java new file mode 100644 index 0000000000..5e555d7b86 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/EchoHttp2ClientHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; + +/** + * HTTP/2 handler that echoes each request DATA frame back as a response DATA frame before the request + * stream ends: response HEADERS on request HEADERS, then every inbound DATA frame mirrored, with END_STREAM + * on the response only once the request's END_STREAM is seen. Drives full-duplex streaming, since the + * response body is produced while the request body is still open. + */ +public class EchoHttp2ClientHandler implements Http2ClientHandler { + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "application/octet-stream"); + // Response headers only; the body is streamed back as request DATA frames arrive. + ctx.writeAndFlush(new DefaultHttp2HeadersFrame(headers, false)); + + // An empty-bodied request (END_STREAM on HEADERS) gets an immediate empty, end-of-stream response. + if (frame.isEndStream()) { + ctx.writeAndFlush(new DefaultHttp2DataFrame(true)); + } + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + // Echo this chunk's payload straight back, retaining the request's END_STREAM flag so the response + // ends exactly when the request does. + ByteBuf echoed = Unpooled.copiedBuffer(frame.content()); + ctx.writeAndFlush(new DefaultHttp2DataFrame(echoed, frame.isEndStream())); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/GoawayAfterFirstRequestHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/GoawayAfterFirstRequestHandler.java new file mode 100644 index 0000000000..6b92bddd19 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/GoawayAfterFirstRequestHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2GoAwayFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2Error; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * HTTP/2 handler that sends GOAWAY after first request on each connection. + */ +public class GoawayAfterFirstRequestHandler implements Http2ClientHandler { + + private final Set seenConnections = ConcurrentHashMap.newKeySet(); + private final String responseBody; + + public GoawayAfterFirstRequestHandler(String responseBody) { + this.responseBody = responseBody; + } + + public int connectionCount() { + return seenConnections.size(); + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var connectionChannel = ctx.channel().parent(); + boolean firstRequest = seenConnections.add(connectionChannel.id()); + + // Send normal response + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "text/plain"); + byte[] body = responseBody.getBytes(StandardCharsets.UTF_8); + headers.setInt("content-length", body.length); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(body), true)); + + // Send GOAWAY after first request (with delay to let response complete) + if (firstRequest) { + ctx.executor() + .schedule( + () -> connectionChannel.writeAndFlush(new DefaultHttp2GoAwayFrame(Http2Error.NO_ERROR)), + 100, + java.util.concurrent.TimeUnit.MILLISECONDS); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandler.java new file mode 100644 index 0000000000..7b65a3497b --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; + +/** + * Handler interface for HTTP/2 requests in the test server. + */ +public interface Http2ClientHandler { + + /** + * Called when HTTP/2 HEADERS frame is received. + * + * @param ctx the channel handler context + * @param frame the headers frame + */ + default void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) {} + + /** + * Called when HTTP/2 DATA frame is received. + * + * @param ctx the channel handler context + * @param frame the data frame + */ + default void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) {} + + /** + * Called when an exception occurs during request processing. + * + * @param ctx the channel handler context + * @param cause the exception + */ + default void onException(ChannelHandlerContext ctx, Throwable cause) { + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandlerFactory.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandlerFactory.java new file mode 100644 index 0000000000..6576b03cf4 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ClientHandlerFactory.java @@ -0,0 +1,13 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; + +@FunctionalInterface +public interface Http2ClientHandlerFactory { + Http2ClientHandler create(ChannelHandlerContext ctx); +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ConnectionFrameHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ConnectionFrameHandler.java new file mode 100644 index 0000000000..f5342ae9b2 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2ConnectionFrameHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http2.Http2GoAwayFrame; +import io.netty.handler.codec.http2.Http2PingFrame; +import io.netty.handler.codec.http2.Http2SettingsAckFrame; +import io.netty.handler.codec.http2.Http2SettingsFrame; +import software.amazon.smithy.java.http.client.it.server.NettyTestLogger; + +public class Http2ConnectionFrameHandler extends ChannelInboundHandlerAdapter { + private static final NettyTestLogger LOGGER = NettyTestLogger.getLogger(Http2ConnectionFrameHandler.class); + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof Http2SettingsFrame settingsFrame) { + // SETTINGS are automatically acknowledged by Http2FrameCodec + LOGGER.info(ctx.channel(), "Received SETTINGS frame: {}", settingsFrame.settings()); + } else if (msg instanceof Http2PingFrame) { + // PING responses are automatically handled by Http2FrameCodec + LOGGER.info(ctx.channel(), "Received PING frame"); + } else if (msg instanceof Http2GoAwayFrame goAwayFrame) { + LOGGER.info(ctx.channel(), + "Received GOAWAY frame, error code: {}, last streamId: {}", + goAwayFrame.errorCode(), + goAwayFrame.lastStreamId()); + } else if (msg instanceof Http2SettingsAckFrame) { + LOGGER.info(ctx.channel(), "Received settings ack frame"); + } else { + // Unknown connection-level frame + LOGGER.warn(ctx.channel(), "Received an unknown message: {}", msg); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + LOGGER.warn(ctx.channel(), "Exception caught, closing context", cause); + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2StreamFrameHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2StreamFrameHandler.java new file mode 100644 index 0000000000..d1d3aded39 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/Http2StreamFrameHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2Frame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import software.amazon.smithy.java.http.client.it.server.NettyTestLogger; +import software.amazon.smithy.java.http.client.it.server.ServerInitializer; + +public class Http2StreamFrameHandler extends SimpleChannelInboundHandler { + + private static final NettyTestLogger LOGGER = NettyTestLogger.getLogger(Http2StreamFrameHandler.class); + private final ServerInitializer.Http2ClientHandlers handlers; + + public Http2StreamFrameHandler(ServerInitializer.Http2ClientHandlers h2ClientHandlers) { + this.handlers = h2ClientHandlers; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) { + if (frame instanceof Http2HeadersFrame headersFrame) { + LOGGER.info(ctx.channel(), "received HTTP/2 headers frame"); + onHeadersRead(ctx, headersFrame); + var handler = handlers.create(ctx); + handler.onHeadersFrame(ctx, headersFrame); + } else if (frame instanceof Http2DataFrame dataFrame) { + LOGGER.info(ctx.channel(), "received HTTP/2 data frame"); + onDataRead(ctx, dataFrame); + var handler = handlers.get(ctx); + handler.onDataFrame(ctx, dataFrame); + } else { + LOGGER.warn(ctx.channel(), "unexpected frame: {}", frame); + } + } + + private void onHeadersRead(ChannelHandlerContext ctx, Http2HeadersFrame headersFrame) { + var headers = headersFrame.headers(); + var method = headers.method().toString(); + var path = headers.path().toString(); + + LOGGER.debug(ctx.channel(), "Received HTTP/2 request for method: {}, path: {}", method, path); + } + + private void onDataRead(ChannelHandlerContext ctx, Http2DataFrame dataFrame) { + LOGGER.debug(ctx.channel(), "Received data with {} bytes", dataFrame.content().readableBytes()); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + var handler = handlers.get(ctx); + handler.onException(ctx, cause); + LOGGER.warn(ctx.channel(), "Exception caught, closing context", cause); + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/LargeResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/LargeResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..98ab21eeb3 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/LargeResponseHttp2ClientHandler.java @@ -0,0 +1,58 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; + +/** + * HTTP/2 handler that sends a large response body in chunks. + */ +public class LargeResponseHttp2ClientHandler implements Http2ClientHandler { + + private final int responseSize; + private final int chunkSize; + + public LargeResponseHttp2ClientHandler(int responseSize, int chunkSize) { + this.responseSize = responseSize; + this.chunkSize = chunkSize; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + // Send response headers + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "application/octet-stream"); + headers.setInt("content-length", responseSize); + ctx.write(new DefaultHttp2HeadersFrame(headers)); + + // Send body in chunks + int remaining = responseSize; + while (remaining > 0) { + int size = Math.min(chunkSize, remaining); + byte[] chunk = new byte[size]; + // Fill with predictable pattern for verification + for (int i = 0; i < size; i++) { + chunk[i] = (byte) ((responseSize - remaining + i) & 0xFF); + } + boolean endStream = (remaining - size) == 0; + ctx.write(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(chunk), endStream)); + remaining -= size; + } + ctx.flush(); + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/MultiplexingHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/MultiplexingHttp2ClientHandler.java new file mode 100644 index 0000000000..7767ea1ca3 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/MultiplexingHttp2ClientHandler.java @@ -0,0 +1,41 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.util.Arrays; +import java.util.List; + +public class MultiplexingHttp2ClientHandler implements Http2ClientHandler { + private final List handlers; + + public MultiplexingHttp2ClientHandler(Http2ClientHandler... handler) { + this.handlers = Arrays.asList(handler); + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + for (var handler : handlers) { + handler.onHeadersFrame(ctx, frame); + } + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + for (var handler : handlers) { + handler.onDataFrame(ctx, frame); + } + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + for (var handler : handlers) { + handler.onException(ctx, cause); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/PartialResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/PartialResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..99309990be --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/PartialResponseHttp2ClientHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.nio.charset.StandardCharsets; + +/** + * HTTP/2 handler that sends partial response then closes connection. + */ +public class PartialResponseHttp2ClientHandler implements Http2ClientHandler { + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.setInt("content-length", 1000); // Claim 1000 bytes + ctx.write(new DefaultHttp2HeadersFrame(headers)); + + // Send only partial data (100 bytes), don't set endStream + byte[] partial = "partial".repeat(14).getBytes(StandardCharsets.UTF_8); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(partial), false)); + + // Close connection abruptly + ctx.channel().parent().close(); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RequestCapturingHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RequestCapturingHttp2ClientHandler.java new file mode 100644 index 0000000000..a1ae2a3910 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RequestCapturingHttp2ClientHandler.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public class RequestCapturingHttp2ClientHandler implements Http2ClientHandler { + private final CompletableFuture streamCompleted = new CompletableFuture<>(); + private final Map> capturedHeaders = new HashMap<>(); + private final ByteArrayOutputStream capturedBody = new ByteArrayOutputStream(); + private Throwable cause; + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var headers = frame.headers(); + for (var kvp : headers) { + var key = kvp.getKey().toString(); + var value = kvp.getValue().toString(); + capturedHeaders.computeIfAbsent(key, k -> new ArrayList<>()).add(value); + } + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + try { + var content = frame.content(); + var bytes = new byte[content.readableBytes()]; + content.readBytes(bytes); + capturedBody.write(bytes); + if (frame.isEndStream()) { + streamCompleted.complete(true); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onException(ChannelHandlerContext ctx, Throwable cause) { + this.cause = cause; + streamCompleted.completeExceptionally(cause); + } + + public Throwable cause() { + return cause; + } + + public Map> capturedHeaders() { + return capturedHeaders; + } + + public ByteArrayOutputStream capturedBody() { + return capturedBody; + } + + public CompletableFuture streamCompleted() { + return streamCompleted; + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RstStreamHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RstStreamHttp2ClientHandler.java new file mode 100644 index 0000000000..19cbc2cc5c --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/RstStreamHttp2ClientHandler.java @@ -0,0 +1,29 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2ResetFrame; +import io.netty.handler.codec.http2.Http2Error; +import io.netty.handler.codec.http2.Http2HeadersFrame; + +/** + * HTTP/2 handler that sends RST_STREAM after receiving headers. + */ +public class RstStreamHttp2ClientHandler implements Http2ClientHandler { + + private final Http2Error errorCode; + + public RstStreamHttp2ClientHandler(Http2Error errorCode) { + this.errorCode = errorCode; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + // Send RST_STREAM instead of response + ctx.writeAndFlush(new DefaultHttp2ResetFrame(errorCode)); + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/StreamingResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/StreamingResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..8cf1468d00 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/StreamingResponseHttp2ClientHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * HTTP/2 handler that sends response in chunks with delays. + */ +public class StreamingResponseHttp2ClientHandler implements Http2ClientHandler { + + private final List chunks; + private final long delayBetweenChunksMs; + + public StreamingResponseHttp2ClientHandler(List chunks, long delayBetweenChunksMs) { + this.chunks = chunks; + this.delayBetweenChunksMs = delayBetweenChunksMs; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var headers = new DefaultHttp2Headers(); + headers.status("200"); + headers.set("content-type", "text/plain"); + ctx.writeAndFlush(new DefaultHttp2HeadersFrame(headers)); + + // Send chunks with delays + for (int i = 0; i < chunks.size(); i++) { + final int index = i; + final boolean isLast = (i == chunks.size() - 1); + ctx.executor().schedule(() -> { + byte[] data = chunks.get(index).getBytes(StandardCharsets.UTF_8); + ctx.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.wrappedBuffer(data), isLast)); + }, delayBetweenChunksMs * i, TimeUnit.MILLISECONDS); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TextResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TextResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..0c646fa8d9 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TextResponseHttp2ClientHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.util.CharsetUtil; +import software.amazon.smithy.java.http.client.it.server.NettyTestLogger; + +public class TextResponseHttp2ClientHandler implements Http2ClientHandler { + private static final NettyTestLogger LOGGER = NettyTestLogger.getLogger(TextResponseHttp2ClientHandler.class); + private final String message; + + public TextResponseHttp2ClientHandler(String message) { + this.message = message; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + var responseHeaders = new DefaultHttp2Headers(); + responseHeaders.status("200"); + responseHeaders.set("content-type", "text/plain"); + ctx.write(new DefaultHttp2HeadersFrame(responseHeaders, false)); + var content = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8); + var endStream = frame.isEndStream(); + LOGGER.info(ctx.channel(), "headers received, sending response, end stream: {}", endStream); + ctx.writeAndFlush(new DefaultHttp2DataFrame(content, endStream)); + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + LOGGER.info(ctx.channel(), "data frame received, closing response"); + if (frame.isEndStream()) { + ctx.writeAndFlush(new DefaultHttp2DataFrame(true)); + } + } +} diff --git a/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TrailerResponseHttp2ClientHandler.java b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TrailerResponseHttp2ClientHandler.java new file mode 100644 index 0000000000..fe7dd4a625 --- /dev/null +++ b/http/http-client/src/it/java/software/amazon/smithy/java/http/client/it/server/h2/TrailerResponseHttp2ClientHandler.java @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.it.server.h2; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.util.CharsetUtil; +import java.util.Map; + +/** + * HTTP/2 handler that sends response with trailer headers. + */ +public class TrailerResponseHttp2ClientHandler implements Http2ClientHandler { + + private final String body; + private final Map trailers; + + public TrailerResponseHttp2ClientHandler(String body, Map trailers) { + this.body = body; + this.trailers = trailers; + } + + @Override + public void onHeadersFrame(ChannelHandlerContext ctx, Http2HeadersFrame frame) { + if (frame.isEndStream()) { + sendResponse(ctx); + } + } + + @Override + public void onDataFrame(ChannelHandlerContext ctx, Http2DataFrame frame) { + if (frame.isEndStream()) { + sendResponse(ctx); + } + } + + private void sendResponse(ChannelHandlerContext ctx) { + // Send response headers (not end of stream) + var responseHeaders = new DefaultHttp2Headers(); + responseHeaders.status("200"); + responseHeaders.set("content-type", "text/plain"); + ctx.write(new DefaultHttp2HeadersFrame(responseHeaders, false)); + + // Send body (not end of stream) + var content = Unpooled.copiedBuffer(body, CharsetUtil.UTF_8); + ctx.write(new DefaultHttp2DataFrame(content, false)); + + // Send trailers (end of stream) + var trailerHeaders = new DefaultHttp2Headers(); + for (var entry : trailers.entrySet()) { + trailerHeaders.set(entry.getKey(), entry.getValue()); + } + ctx.writeAndFlush(new DefaultHttp2HeadersFrame(trailerHeaders, true)); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/BenchmarkSupport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/BenchmarkSupport.java index 154b10f9c7..ef0b64cae5 100644 --- a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/BenchmarkSupport.java +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/BenchmarkSupport.java @@ -6,14 +6,15 @@ package software.amazon.smithy.java.http.client; import java.io.OutputStream; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse.BodyHandlers; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -23,39 +24,82 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.io.uri.SmithyUri; /** - * Shared utilities for JDK transport benchmarks. + * Shared utilities for HTTP client benchmarks. + * This class is not a benchmark - JMH only measures @Benchmark methods. */ public final class BenchmarkSupport { - static { - System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host"); + /** + * Override the benchmark server host with {@code -Djmh.bench.host=} or + * {@code BENCH_HOST=} env var. Defaults to {@code localhost}. The Gradle + * jmh task does NOT auto-start the benchmark server when this is set to anything + * other than {@code localhost} — start the server yourself on the remote host. + */ + public static final String BENCH_HOST = resolveHost(); + public static final int H1_PORT = 18080; + public static final int H2C_PORT = 18081; + public static final int H2_PORT = 18443; + + public static final String H1_URL = "http://" + BENCH_HOST + ":" + H1_PORT; + public static final String H2C_URL = "http://" + BENCH_HOST + ":" + H2C_PORT; + public static final String H2_URL = "https://" + BENCH_HOST + ":" + H2_PORT; + public static final String H2C_AUTHORITY = BENCH_HOST + ":" + H2C_PORT; + public static final String H2_AUTHORITY = BENCH_HOST + ":" + H2_PORT; + + private static String resolveHost() { + String prop = System.getProperty("jmh.bench.host"); + if (prop != null && !prop.isBlank()) { + return prop.trim(); + } + String env = System.getenv("BENCH_HOST"); + if (env != null && !env.isBlank()) { + return env.trim(); + } + return "localhost"; } - public static final String H1_URL = "http://localhost:18080"; - public static final String H2C_URL = "http://localhost:18081"; - public static final String H2_URL = "https://localhost:18443"; - + // Small JSON payload for POST benchmarks public static final byte[] POST_PAYLOAD = "{\"id\":12345,\"name\":\"benchmark\"}".getBytes(StandardCharsets.UTF_8); + + // 1MB payload for large transfer benchmarks public static final byte[] MB_PAYLOAD = new byte[1024 * 1024]; private BenchmarkSupport() {} public record IoStats(long getMbRequests, long getMbBytesSent, long putMbRequests, long putMbBytesReceived) {} + /** + * Create a DNS resolver that maps the configured BENCH_HOST to its resolved address, + * avoiding repeated DNS lookups in the hot path. Defaults to localhost → loopback. + */ + public static DnsResolver staticDns() { + try { + InetAddress[] addrs = "localhost".equals(BENCH_HOST) + ? new InetAddress[] {InetAddress.getLoopbackAddress()} + : InetAddress.getAllByName(BENCH_HOST); + return DnsResolver.staticMapping(Map.of(BENCH_HOST, List.of(addrs))); + } catch (UnknownHostException e) { + throw new RuntimeException("Cannot resolve benchmark host: " + BENCH_HOST, e); + } + } + + /** + * Create an SSL context that trusts all certificates (for benchmarking only). + */ public static SSLContext trustAllSsl() throws Exception { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - @Override public void checkClientTrusted(X509Certificate[] certs, String authType) {} - @Override public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; @@ -65,23 +109,39 @@ public void checkServerTrusted(X509Certificate[] certs, String authType) {} return sslContext; } + /** + * Reset server state and trigger GC. + */ public static void resetServer(HttpClient client, String baseUrl) throws Exception { - sendAndDrain(client, baseUrl + "/reset", "POST"); - sendAndDrain(client, baseUrl + "/reset-io-stats", "POST"); + try (var res = client.send(HttpRequest.create() + .setUri(SmithyUri.of(baseUrl + "/reset")) + .setMethod("POST"))) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + try (var res = client.send(HttpRequest.create() + .setUri(SmithyUri.of(baseUrl + "/reset-io-stats")) + .setMethod("POST"))) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } Thread.sleep(100); } + /** + * Get server stats as JSON string. + */ public static String getServerStats(HttpClient client, String baseUrl) throws Exception { - return getServerStats(client, baseUrl, null); + try (var res = client.send(HttpRequest.create() + .setUri(SmithyUri.of(baseUrl + "/stats")) + .setMethod("GET"))) { + return new String(res.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8); + } } - public static String getServerStats(HttpClient client, String baseUrl, String runId) - throws Exception { - String url = runId == null ? baseUrl + "/stats" : baseUrl + "/stats?runId=" + runId; - var request = HttpRequest.newBuilder().uri(URI.create(url)).GET().build(); - var response = client.send(request, BodyHandlers.ofInputStream()); - try (var body = response.body()) { - return new String(body.readAllBytes(), StandardCharsets.UTF_8); + public static String getServerStats(HttpClient client, String baseUrl, String runId) throws Exception { + try (var res = client.send(HttpRequest.create() + .setUri(SmithyUri.of(baseUrl + "/stats?runId=" + runId)) + .setMethod("GET"))) { + return new String(res.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8); } } @@ -103,6 +163,15 @@ public static void assertIoStats(String label, IoStats actual, IoStats expected) } } + /** + * Run a benchmark loop with virtual threads until totalRequests is reached. + * + * @param concurrency number of virtual threads generating load + * @param totalRequests total requests to complete before stopping + * @param task the task each thread runs in a loop + * @param context context passed to task (avoids lambda allocation) + * @param counter output counter for requests/errors + */ public static void runBenchmark( int concurrency, int totalRequests, @@ -135,7 +204,9 @@ public static void runBenchmark( }); } - if (!latch.await(10, TimeUnit.SECONDS)) { + // Safety net only; normal completion releases the latch immediately. Generous enough that a + // high-concurrency invocation (thousands of 1 MB transfers) never false-times-out. + if (!latch.await(120, TimeUnit.SECONDS)) { Throwable err = firstError.get(); System.err.println("BENCHMARK TIMEOUT: " + (concurrency - (int) latch.getCount()) + "/" + concurrency + " threads completed, errors=" + errors.get() @@ -156,11 +227,16 @@ public interface BenchmarkTask { void run(T context) throws Exception; } + /** + * Simple counter for benchmark results. Used with @AuxCounters. + * JMH picks up public fields OR getter methods for aux counters. + */ public static class RequestCounter { public long requests; public long errors; public Throwable firstError; + // Getter methods for JMH aux counters (some versions need these) public long requests() { return requests; } @@ -186,24 +262,53 @@ public void throwIfErrored(String label) { if (firstError == null) { return; } + if (firstError instanceof RuntimeException runtimeException) { + throw new IllegalStateException(label + " failed with " + errors + " error(s)", runtimeException); + } throw new IllegalStateException(label + " failed with " + errors + " error(s)", firstError); } } + /** + * Extract H2ConnectionStats from the client via reflection. + */ public static String getH2ConnectionStats(HttpClient client) { - return "(stats unavailable for java.net.http.HttpClient)"; - } - - private static void sendAndDrain(HttpClient client, String url, String method) throws Exception { - var builder = HttpRequest.newBuilder().uri(URI.create(url)); - if ("POST".equals(method)) { - builder.POST(HttpRequest.BodyPublishers.noBody()); - } else { - builder.GET(); - } - var response = client.send(builder.build(), BodyHandlers.ofInputStream()); - try (var body = response.body()) { - body.transferTo(OutputStream.nullOutputStream()); + try { + // HttpClient -> DefaultHttpClient.pool -> HttpConnectionPool.h2Manager -> H2ConnectionManager.routes + var poolField = client.getClass().getDeclaredField("connectionPool"); + poolField.setAccessible(true); + var pool = poolField.get(client); + + var h2Field = pool.getClass().getDeclaredField("h2Manager"); + h2Field.setAccessible(true); + var h2Manager = h2Field.get(pool); + + var routesField = h2Manager.getClass().getDeclaredField("routes"); + routesField.setAccessible(true); + var routes = (ConcurrentHashMap) routesField.get(h2Manager); + + var sb = new StringBuilder(); + for (var entry : routes.values()) { + var connsField = entry.getClass().getDeclaredField("conns"); + connsField.setAccessible(true); + var conns = (Object[]) connsField.get(entry); + for (var conn : conns) { + if (conn != null) { + var statsMethod = conn.getClass().getDeclaredMethod("getStats"); + statsMethod.setAccessible(true); + var stats = statsMethod.invoke(conn); + if (stats != null) { + if (!sb.isEmpty()) { + sb.append("; "); + } + sb.append(stats); + } + } + } + } + return sb.isEmpty() ? "(no stats)" : sb.toString(); + } catch (Exception e) { + return "(stats unavailable: " + e.getMessage() + ")"; } } diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H1ScalingBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H1ScalingBenchmark.java new file mode 100644 index 0000000000..e10a732158 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H1ScalingBenchmark.java @@ -0,0 +1,308 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import io.helidon.webclient.api.HttpClientResponse; +import io.helidon.webclient.api.WebClient; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse.BodyHandlers; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.io.entity.ByteArrayEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.util.Timeout; +import org.openjdk.jmh.annotations.AuxCounters; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import software.amazon.smithy.java.client.http.JavaHttpClientTransport; +import software.amazon.smithy.java.context.Context; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * HTTP/1.1 client scaling benchmark. + * + *

For H1, the key parameters are: + *

    + *
  • concurrency - number of virtual threads making requests
  • + *
  • maxConnections - connection pool size (caps actual parallelism)
  • + *
+ * + *

Run with: ./gradlew :http:http-client:jmh -Pjmh.includes="H1ScalingBenchmark" + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@Warmup(iterations = 2, time = 3) +@Measurement(iterations = 3, time = 5) +@Fork(value = 1, jvmArgs = {"-Xms2g", "-Xmx2g"}) +@State(Scope.Benchmark) +public class H1ScalingBenchmark { + + /** Total requests issued per @Benchmark invocation; matched on each smithy method via @OperationsPerInvocation. */ + private static final int OPS = 1000; + + @Param({"1", "10", "100"}) + private int concurrency; + + @Param({"50", "100"}) + private int maxConnections; + + private HttpClient smithyClient; + private CloseableHttpClient apacheClient; + private WebClient helidonClient; + private java.net.http.HttpClient javaClient; + private JavaHttpClientTransport javaTransport; + private Context transportContext; + + // Pre-built requests (read-only during benchmark) + private HttpRequest smithyGetRequest; + private HttpRequest smithyPostRequest; + private java.net.http.HttpRequest jdkGetRequest; + private java.net.http.HttpRequest jdkPostRequest; + + @Setup(Level.Trial) + public void setupIteration() throws Exception { + closeClients(); + + System.out.println("H1 setup: concurrency=" + concurrency + ", maxConnections=" + maxConnections); + + // Smithy client + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(maxConnections) + .maxTotalConnections(maxConnections) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .dnsResolver(BenchmarkSupport.staticDns()) + .build(); + + // Apache client + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(maxConnections); + connManager.setDefaultMaxPerRoute(maxConnections); + connManager.setDefaultConnectionConfig(ConnectionConfig.custom() + .setConnectTimeout(Timeout.ofSeconds(10)) + .setSocketTimeout(Timeout.ofSeconds(30)) + .build()); + + apacheClient = HttpClients.custom() + .setConnectionManager(connManager) + .setDefaultRequestConfig(RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofSeconds(5)) + .build()) + .build(); + + // Helidon client + helidonClient = WebClient.builder() + .baseUri(BenchmarkSupport.H1_URL) + .shareConnectionCache(false) + .connectionCacheSize(maxConnections) + .build(); + + // Java HttpClient (HTTP/1.1) + javaClient = java.net.http.HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_1_1) + .build(); + javaTransport = new JavaHttpClientTransport(javaClient); + transportContext = Context.create(); + + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H1_URL); + + // Pre-build requests + smithyGetRequest = HttpRequest.create() + .setUri(SmithyUri.of(BenchmarkSupport.H1_URL + "/get")) + .setMethod("GET"); + smithyPostRequest = HttpRequest.create() + .setUri(SmithyUri.of(BenchmarkSupport.H1_URL + "/post")) + .setMethod("POST") + .setBody(DataStream.ofBytes(BenchmarkSupport.POST_PAYLOAD)); + jdkGetRequest = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(BenchmarkSupport.H1_URL + "/get")) + .GET() + .build(); + jdkPostRequest = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(BenchmarkSupport.H1_URL + "/post")) + .POST(BodyPublishers.ofByteArray(BenchmarkSupport.POST_PAYLOAD)) + .build(); + } + + @TearDown(Level.Trial) + public void teardown() throws Exception { + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H1_URL); + System.out.println("H1 stats [c=" + concurrency + ", conn=" + maxConnections + "]: " + stats); + closeClients(); + } + + private void closeClients() throws Exception { + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; + } + if (apacheClient != null) { + apacheClient.close(); + apacheClient = null; + } + if (helidonClient != null) { + helidonClient.closeResource(); + helidonClient = null; + } + if (javaClient != null) { + javaClient.close(); + javaClient = null; + } + if (javaTransport != null) { + javaTransport = null; + } + } + + @AuxCounters(AuxCounters.Type.EVENTS) + @State(Scope.Thread) + public static class Counter extends BenchmarkSupport.RequestCounter { + @Setup(Level.Trial) + public void reset() { + super.reset(); + } + } + + @Benchmark + @Threads(1) + @OperationsPerInvocation(OPS) + public void h1SmithyGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + smithyClient.send(req).close(); + }, smithyGetRequest, counter); + + counter.logErrors("Smithy H1"); + } + + @Benchmark + @Threads(1) + public void h1ApacheGet(Counter counter) throws InterruptedException { + var target = BenchmarkSupport.H1_URL + "/get"; + + BenchmarkSupport.runBenchmark(concurrency, concurrency, (String url) -> { + try (var response = apacheClient.execute(new HttpGet(url))) { + EntityUtils.consume(response.getEntity()); + } + }, target, counter); + + counter.logErrors("Apache H1"); + } + + @Benchmark + @Threads(1) + public void h1HelidonGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, concurrency, (WebClient client) -> { + try (HttpClientResponse response = client.get("/get").request()) { + response.entity().consume(); + } + }, helidonClient, counter); + + counter.logErrors("Helidon H1"); + } + + @Benchmark + @Threads(1) + public void h1JdkGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + var response = javaClient.send(req, BodyHandlers.ofInputStream()); + try (InputStream body = response.body()) { + body.transferTo(OutputStream.nullOutputStream()); + } + }, jdkGetRequest, counter); + + counter.logErrors("Java HttpClient H1"); + } + + @Benchmark + @Threads(1) + public void h1JavaWrapperGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, concurrency, (HttpRequest req) -> { + try (var response = javaTransport.send(transportContext, req)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, smithyGetRequest, counter); + + counter.logErrors("Java Wrapper H1"); + } + + @Benchmark + @Threads(1) + @OperationsPerInvocation(OPS) + public void h1SmithyPost(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + smithyClient.send(req).close(); + }, smithyPostRequest, counter); + + counter.logErrors("Smithy H1 POST"); + } + + @Benchmark + @Threads(1) + public void h1ApachePost(Counter counter) throws InterruptedException { + var target = BenchmarkSupport.H1_URL + "/post"; + + BenchmarkSupport.runBenchmark(concurrency, concurrency, (String url) -> { + var post = new HttpPost(url); + post.setEntity(new ByteArrayEntity(BenchmarkSupport.POST_PAYLOAD, ContentType.APPLICATION_OCTET_STREAM)); + try (var response = apacheClient.execute(post)) { + EntityUtils.consume(response.getEntity()); + } + }, target, counter); + + counter.logErrors("Apache H1 POST"); + } + + @Benchmark + @Threads(1) + public void h1JdkPost(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + var response = javaClient.send(req, BodyHandlers.ofInputStream()); + try (InputStream body = response.body()) { + body.transferTo(OutputStream.nullOutputStream()); + } + }, jdkPostRequest, counter); + + counter.logErrors("Java HttpClient H1 POST"); + } + + @Benchmark + @Threads(1) + public void h1JavaWrapperPost(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, concurrency, (HttpRequest req) -> { + try (var response = javaTransport.send(transportContext, req)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, smithyPostRequest, counter); + + counter.logErrors("Java wrapper H1 POST"); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2MixedGetPutBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2MixedGetPutBenchmark.java index 3bcca581f4..c0d9d1ee11 100644 --- a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2MixedGetPutBenchmark.java +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2MixedGetPutBenchmark.java @@ -6,7 +6,6 @@ package software.amazon.smithy.java.http.client; import java.io.OutputStream; -import java.net.http.HttpClient; import java.time.Duration; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -20,6 +19,7 @@ import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; @@ -29,37 +29,44 @@ import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; import software.amazon.smithy.java.client.http.JavaHttpClientTransport; +import software.amazon.smithy.java.client.http.boringssl.BoringSslTlsProvider; import software.amazon.smithy.java.context.Context; import software.amazon.smithy.java.http.api.HttpRequest; -import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; import software.amazon.smithy.java.io.datastream.DataStream; import software.amazon.smithy.java.io.uri.SmithyUri; /** - * Mixed H2 benchmark that interleaves 1 MB GETs and 1 MB PUTs on the JDK transport. + * Mixed H2 benchmark that interleaves 1 MB GETs and 1 MB PUTs on the same client. */ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @Warmup(iterations = 2, time = 3) @Measurement(iterations = 3, time = 5) -@Fork(value = 1, jvmArgs = {"-Xms2g", "-Xmx2g"}) +@Fork(value = 1, jvmArgs = {"-Xms16g", "-Xmx16g"}) @State(Scope.Benchmark) public class H2MixedGetPutBenchmark { + /** + * Total requests issued per @Benchmark invocation; matched via @OperationsPerInvocation. Must be + * >= the largest {@code concurrency} value so every concurrent virtual thread gets work (the harness + * shares OPS requests across {@code concurrency} workers). + */ + private static final int OPS = 20_000; + @Param({ - "1", - "10" + "5000" }) private int concurrency; - @Param({"1", "3"}) + @Param({"50"}) private int connections; @Param({"4096"}) private int streamsPerConnection; - private HttpClient benchmarkClient; - private HttpClient javaClient; + private HttpClient smithyClient; + private java.net.http.HttpClient javaClient; private ExecutorService javaExecutor; private JavaHttpClientTransport javaTransport; private Context transportContext; @@ -70,29 +77,37 @@ public class H2MixedGetPutBenchmark { public void setup() throws Exception { var sslContext = BenchmarkSupport.trustAllSsl(); - benchmarkClient = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) + if (!BoringSslTlsProvider.available()) { + throw new IllegalStateException("BoringSSL (netty-tcnative) is not available on this host"); + } + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(connections) + .maxTotalConnections(connections) + .h2StreamsPerConnection(streamsPerConnection) + .h2InitialWindowSize(16 * 1024 * 1024) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_2) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(30)) + .tlsProvider(BoringSslTlsProvider.create(true)) + .dnsResolver(BenchmarkSupport.staticDns()) .build(); javaExecutor = Executors.newVirtualThreadPerTaskExecutor(); - javaClient = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) + javaClient = java.net.http.HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_2) .sslContext(sslContext) .executor(javaExecutor) .build(); javaTransport = new JavaHttpClientTransport(javaClient); transportContext = Context.create(); - BenchmarkSupport.resetServer(benchmarkClient, BenchmarkSupport.H2_URL); + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H2_URL); runId = BenchmarkSupport.createRunId("h2-mixed"); mixedRequests = new MixedRequests( new RequestPlan( HttpRequest.create() .setUri(SmithyUri.of(BenchmarkSupport.H2_URL + "/getmb?runId=" + runId)) - .setHttpVersion(HttpVersion.HTTP_2) .setMethod("GET"), true, 0, @@ -100,7 +115,6 @@ public void setup() throws Exception { new RequestPlan( HttpRequest.create() .setUri(SmithyUri.of(BenchmarkSupport.H2_URL + "/putmb?runId=" + runId)) - .setHttpVersion(HttpVersion.HTTP_2) .setMethod("PUT") .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)), false, @@ -111,26 +125,20 @@ public void setup() throws Exception { @TearDown(Level.Trial) public void teardown() throws Exception { try { - if (benchmarkClient != null) { - String stats = BenchmarkSupport.getServerStats(benchmarkClient, BenchmarkSupport.H2_URL, runId); + if (smithyClient != null) { + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H2_URL, runId); var actualStats = BenchmarkSupport.parseIoStats(stats); var expectedStats = mixedRequests.expectedIoStats(); BenchmarkSupport.assertIoStats("H2 mixed server IO stats", actualStats, expectedStats); mixedRequests.assertClientIoMatches(expectedStats); System.out.println("H2 mixed GET+PUT stats [c=" + concurrency + ", conn=" + connections + ", streams=" + streamsPerConnection + "]: " + stats); - System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(benchmarkClient)); - System.out.println("JDK mixed config: executor=vt" - + ", transferScratchSize=" - + Integer.getInteger("smithy.java.client.http.jdk.transferScratchSize", 16 * 1024) - + ", jdk.httpclient.maxframesize=" + System.getProperty("jdk.httpclient.maxframesize") - + ", jdk.httpclient.bufsize=" + System.getProperty("jdk.httpclient.bufsize") - + ", jdk.httpclient.maxstreams=" + System.getProperty("jdk.httpclient.maxstreams")); + System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(smithyClient)); } } finally { - if (benchmarkClient != null) { - benchmarkClient.close(); - benchmarkClient = null; + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; } if (javaClient != null) { javaClient.close(); @@ -140,7 +148,9 @@ public void teardown() throws Exception { javaExecutor.close(); javaExecutor = null; } - javaTransport = null; + if (javaTransport != null) { + javaTransport = null; + } } } @@ -215,11 +225,32 @@ private void assertClientIoMatches(BenchmarkSupport.IoStats expectedStats) { private record RequestPlan(HttpRequest request, boolean isGet, long requestBytes, long responseBytes) {} @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyMixedGetPutMb(Counter counter) throws InterruptedException { + long startGet = mixedRequests.totalGetRequests.get(); + long startPut = mixedRequests.totalPutRequests.get(); + BenchmarkSupport.runBenchmark(concurrency, OPS, (MixedRequests requests) -> { + var request = requests.next(); + try (var response = smithyClient.send(request.request())) { + long responseBytes = response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + requests.recordCompletion(request, responseBytes); + } + }, mixedRequests, counter); + counter.getRequests = mixedRequests.totalGetRequests.get() - startGet; + counter.putRequests = mixedRequests.totalPutRequests.get() - startPut; + + counter.logErrors("Smithy H2 mixed GET+PUT"); + counter.throwIfErrored("Smithy H2 mixed GET+PUT"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JavaWrapperMixedGetPutMb(Counter counter) throws InterruptedException { long startGet = mixedRequests.totalGetRequests.get(); long startPut = mixedRequests.totalPutRequests.get(); - BenchmarkSupport.runBenchmark(concurrency, concurrency * 2, (MixedRequests requests) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (MixedRequests requests) -> { var request = requests.next(); try (var response = javaTransport.send(transportContext, request.request())) { long responseBytes = response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2ScalingBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2ScalingBenchmark.java index 54b442c771..57b8e316f4 100644 --- a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2ScalingBenchmark.java +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2ScalingBenchmark.java @@ -5,14 +5,43 @@ package software.amazon.smithy.java.http.client; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.handler.codec.http2.Http2MultiplexHandler; +import io.netty.handler.codec.http2.Http2SecurityUtil; +import io.netty.handler.codec.http2.Http2Settings; +import io.netty.handler.codec.http2.Http2StreamChannel; +import io.netty.handler.codec.http2.Http2StreamChannelBootstrap; +import io.netty.handler.codec.http2.Http2StreamFrame; +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.ApplicationProtocolNames; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SupportedCipherSuiteFilter; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpClient.Version; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; +import java.nio.ByteBuffer; import java.time.Duration; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -23,6 +52,7 @@ import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; @@ -34,12 +64,15 @@ import software.amazon.smithy.java.client.http.JavaHttpClientTransport; import software.amazon.smithy.java.context.Context; import software.amazon.smithy.java.http.api.HttpRequest; -import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.h2.EventLoopH2Transport; import software.amazon.smithy.java.io.datastream.DataStream; import software.amazon.smithy.java.io.uri.SmithyUri; /** - * HTTP/2 over TLS (h2) benchmark focused on the JDK transport. + * HTTP/2 over TLS (h2) benchmark comparing Smithy and Java HttpClient. + * + *

Run with: ./gradlew :http:http-client:jmh -Pjmh.includes="H2ScalingBenchmark" */ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @@ -49,9 +82,13 @@ @State(Scope.Benchmark) public class H2ScalingBenchmark { + /** Total requests issued per @Benchmark invocation; matched on each method via @OperationsPerInvocation. */ + private static final int OPS = 1000; + @Param({ "1", "10" + //, "100", "1000" }) private int concurrency; @@ -61,14 +98,18 @@ public class H2ScalingBenchmark { @Param({"4096"}) private int streamsPerConnection; - private HttpClient benchmarkClient; - private HttpClient javaClient; + private HttpClient smithyClient; + private java.net.http.HttpClient javaClient; private ExecutorService javaExecutor; private JavaHttpClientTransport javaTransport; + private EventLoopGroup nettyGroup; + private Channel nettyChannel; + private NettyH2Transport nettyTransport; + private EventLoopH2Transport eventLoopTransport; private Context transportContext; @Setup(Level.Trial) - public void setup() throws Exception { + public void setupIteration() throws Exception { closeClients(); System.out.println("H2 setup: concurrency=" + concurrency @@ -77,37 +118,89 @@ public void setup() throws Exception { var sslContext = BenchmarkSupport.trustAllSsl(); - benchmarkClient = HttpClient.newBuilder() - .version(Version.HTTP_2) + // Smithy H2 client + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(connections) + .maxTotalConnections(connections) + .h2StreamsPerConnection(streamsPerConnection) + .h2InitialWindowSize(16 * 1024 * 1024) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_2) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(30)) + .dnsResolver(BenchmarkSupport.staticDns()) .build(); + // Java HttpClient (HTTP/2 over TLS) javaExecutor = Executors.newVirtualThreadPerTaskExecutor(); - javaClient = HttpClient.newBuilder() - .version(Version.HTTP_2) + javaClient = java.net.http.HttpClient.newBuilder() + .version(java.net.http.HttpClient.Version.HTTP_2) .sslContext(sslContext) .executor(javaExecutor) .build(); javaTransport = new JavaHttpClientTransport(javaClient); - transportContext = Context.create(); - BenchmarkSupport.resetServer(benchmarkClient, BenchmarkSupport.H2_URL); + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H2_URL); + + // Netty H2 client + SslContext nettySslCtx = SslContextBuilder.forClient() + .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2)) + .build(); + + nettyGroup = new NioEventLoopGroup(1); + var h2FrameCodec = Http2FrameCodecBuilder.forClient() + .initialSettings(Http2Settings.defaultSettings() + .initialWindowSize(1024 * 1024) + .maxConcurrentStreams(4096)) + .build(); + + Bootstrap b = new Bootstrap(); + b.group(nettyGroup) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline() + .addLast(nettySslCtx + .newHandler(ch.alloc(), BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2_PORT)); + ch.pipeline().addLast(h2FrameCodec); + ch.pipeline() + .addLast(new Http2MultiplexHandler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) {} + })); + } + }); + nettyChannel = b.connect(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2_PORT).sync().channel(); + + // Netty-backed Smithy transport prototype + nettyTransport = new NettyH2Transport(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2_PORT); + + // Event-loop prototype (Phase 1+2: non-blocking TLS + single-thread H2) + eventLoopTransport = new EventLoopH2Transport(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2_PORT); + + transportContext = Context.create(); } @TearDown(Level.Trial) public void teardown() throws Exception { - String stats = BenchmarkSupport.getServerStats(benchmarkClient, BenchmarkSupport.H2_URL); + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H2_URL); System.out.println("H2 stats [c=" + concurrency + ", conn=" + connections + ", streams=" + streamsPerConnection + "]: " + stats); - System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(benchmarkClient)); + System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(smithyClient)); closeClients(); } private void closeClients() throws Exception { - if (benchmarkClient != null) { - benchmarkClient.close(); - benchmarkClient = null; + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; } if (javaClient != null) { javaClient.close(); @@ -117,7 +210,25 @@ private void closeClients() throws Exception { javaExecutor.close(); javaExecutor = null; } - javaTransport = null; + if (javaTransport != null) { + javaTransport = null; + } + if (nettyChannel != null) { + nettyChannel.close().sync(); + nettyChannel = null; + } + if (nettyGroup != null) { + nettyGroup.shutdownGracefully().sync(); + nettyGroup = null; + } + if (nettyTransport != null) { + nettyTransport.close(); + nettyTransport = null; + } + if (eventLoopTransport != null) { + eventLoopTransport.close(); + eventLoopTransport = null; + } } @AuxCounters(AuxCounters.Type.EVENTS) @@ -130,6 +241,23 @@ public void reset() { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyGet(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/get"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JdkGet(Counter counter) throws InterruptedException { var request = java.net.http.HttpRequest.newBuilder() @@ -137,7 +265,7 @@ public void h2JdkGet(Counter counter) throws InterruptedException { .GET() .build(); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (java.net.http.HttpRequest req) -> { var response = javaClient.send(req, BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { body.transferTo(OutputStream.nullOutputStream()); @@ -148,6 +276,141 @@ public void h2JdkGet(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2NettyGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Channel ch) -> { + var streamBootstrap = new Http2StreamChannelBootstrap(ch); + var future = new CompletableFuture(); + Http2StreamChannel stream = streamBootstrap.open().sync().getNow(); + stream.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) { + if (msg instanceof Http2DataFrame data) { + // Consume data + if (data.isEndStream()) { + future.complete(null); + } + } else if (msg instanceof Http2HeadersFrame headers) { + if (headers.isEndStream()) { + future.complete(null); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + future.completeExceptionally(cause); + } + }); + + var headers = new DefaultHttp2Headers() + .method("GET") + .path("/get") + .scheme("https") + .authority(BenchmarkSupport.H2_AUTHORITY); + stream.writeAndFlush(new DefaultHttp2HeadersFrame(headers, true)); + future.join(); + }, nettyChannel, counter); + + counter.logErrors("Netty H2"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2NettyPost(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Channel ch) -> { + var future = new CompletableFuture(); + Http2StreamChannel stream = new Http2StreamChannelBootstrap(ch).open().sync().getNow(); + stream.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) { + if (msg instanceof Http2DataFrame data && data.isEndStream()) { + future.complete(null); + } else if (msg instanceof Http2HeadersFrame headers && headers.isEndStream()) { + future.complete(null); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + future.completeExceptionally(cause); + } + }); + var headers = new DefaultHttp2Headers() + .method("POST") + .path("/post") + .scheme("https") + .authority(BenchmarkSupport.H2_AUTHORITY); + stream.write(new DefaultHttp2HeadersFrame(headers, false)); + stream.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(BenchmarkSupport.POST_PAYLOAD), + true)); + future.join(); + }, nettyChannel, counter); + + counter.logErrors("Netty H2 POST"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2NettyPutMb(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Channel ch) -> { + var future = new CompletableFuture(); + Http2StreamChannel stream = new Http2StreamChannelBootstrap(ch).open().sync().getNow(); + stream.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) { + if (msg instanceof Http2DataFrame data && data.isEndStream()) { + future.complete(null); + } else if (msg instanceof Http2HeadersFrame headers && headers.isEndStream()) { + future.complete(null); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + future.completeExceptionally(cause); + } + }); + var headers = new DefaultHttp2Headers() + .method("PUT") + .path("/putmb") + .scheme("https") + .authority(BenchmarkSupport.H2_AUTHORITY); + stream.write(new DefaultHttp2HeadersFrame(headers, false)); + stream.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(BenchmarkSupport.MB_PAYLOAD), + true)); + future.join(); + }, nettyChannel, counter); + + counter.logErrors("Netty H2 PUT 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyPost(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/post"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("POST") + .setBody(DataStream.ofBytes(BenchmarkSupport.POST_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2 POST"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JdkPost(Counter counter) throws InterruptedException { var request = java.net.http.HttpRequest.newBuilder() @@ -155,7 +418,7 @@ public void h2JdkPost(Counter counter) throws InterruptedException { .POST(BodyPublishers.ofByteArray(BenchmarkSupport.POST_PAYLOAD)) .build(); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (java.net.http.HttpRequest req) -> { var response = javaClient.send(req, BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { body.transferTo(OutputStream.nullOutputStream()); @@ -166,6 +429,62 @@ public void h2JdkPost(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyPutMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/putmb"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("PUT") + .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2 PUT 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyNettyPutMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/putmb"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("PUT") + .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + var res = nettyTransport.send(req); + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + }, request, counter); + + counter.logErrors("Smithy-on-Netty H2 PUT 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyEventLoopPutMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/putmb"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("PUT") + .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + var res = eventLoopTransport.send(req); + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + }, request, counter); + + counter.logErrors("Smithy-EventLoop H2 PUT 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JdkPutMb(Counter counter) throws InterruptedException { var request = java.net.http.HttpRequest.newBuilder() @@ -173,7 +492,7 @@ public void h2JdkPutMb(Counter counter) throws InterruptedException { .PUT(BodyPublishers.ofByteArray(BenchmarkSupport.MB_PAYLOAD)) .build(); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (java.net.http.HttpRequest req) -> { var response = javaClient.send(req, BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { body.transferTo(OutputStream.nullOutputStream()); @@ -184,16 +503,16 @@ public void h2JdkPutMb(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JavaWrapperPutMb(Counter counter) throws InterruptedException { var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/putmb"); var request = HttpRequest.create() .setUri(uri) - .setHttpVersion(HttpVersion.HTTP_2) .setMethod("PUT") .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { try (var response = javaTransport.send(transportContext, req)) { response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); } @@ -203,12 +522,29 @@ public void h2JavaWrapperPutMb(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyGetMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/getmb"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2 GET 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JavaWrapperGetMb(Counter counter) throws InterruptedException { var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/getmb"); - var request = HttpRequest.create().setUri(uri).setHttpVersion(HttpVersion.HTTP_2).setMethod("GET"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { try (var response = javaTransport.send(transportContext, req)) { response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); } @@ -218,14 +554,35 @@ public void h2JavaWrapperGetMb(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyGetMbChannel(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/getmb"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + var drainBuf = ByteBuffer.allocate(65536); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + var ch = res.body().asChannel(); + while (ch.read(drainBuf) >= 0) { + drainBuf.clear(); + } + } + }, request, counter); + + counter.logErrors("Smithy H2 GET 1MB (channel)"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JdkGetMb(Counter counter) throws InterruptedException { var request = java.net.http.HttpRequest.newBuilder() - .uri(URI.create(BenchmarkSupport.H2_URL + "/getmb")) + .uri(java.net.URI.create(BenchmarkSupport.H2_URL + "/getmb")) .GET() .build(); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (java.net.http.HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (java.net.http.HttpRequest req) -> { var response = javaClient.send(req, BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { body.transferTo(OutputStream.nullOutputStream()); @@ -236,12 +593,68 @@ public void h2JdkGetMb(Counter counter) throws InterruptedException { } @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2NettyGetMb(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Channel ch) -> { + var future = new CompletableFuture(); + Http2StreamChannel stream = new Http2StreamChannelBootstrap(ch).open().sync().getNow(); + stream.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) { + if (msg instanceof Http2DataFrame data) { + if (data.isEndStream()) { + future.complete(null); + } + } else if (msg instanceof Http2HeadersFrame headers) { + if (headers.isEndStream()) { + future.complete(null); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + future.completeExceptionally(cause); + } + }); + + var headers = new DefaultHttp2Headers() + .method("GET") + .path("/getmb") + .scheme("https") + .authority(BenchmarkSupport.H2_AUTHORITY); + stream.writeAndFlush(new DefaultHttp2HeadersFrame(headers, true)); + future.join(); + }, nettyChannel, counter); + + counter.logErrors("Netty H2 GET 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyGet10Mb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/get10mb"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2 GET 10MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) @Threads(1) public void h2JavaWrapperGet10Mb(Counter counter) throws InterruptedException { var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/get10mb"); - var request = HttpRequest.create().setUri(uri).setHttpVersion(HttpVersion.HTTP_2).setMethod("GET"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); - BenchmarkSupport.runBenchmark(concurrency, concurrency, (HttpRequest req) -> { + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { try (var response = javaTransport.send(transportContext, req)) { response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); } @@ -249,4 +662,60 @@ public void h2JavaWrapperGet10Mb(Counter counter) throws InterruptedException { counter.logErrors("Java Wrapper H2 GET 10MB"); } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2SmithyGet10MbChannel(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2_URL + "/get10mb"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + var drainBuf = ByteBuffer.allocate(65536); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + var ch = res.body().asChannel(); + while (ch.read(drainBuf) >= 0) { + drainBuf.clear(); + } + } + }, request, counter); + + counter.logErrors("Smithy H2 GET 10MB (channel)"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2NettyGet10Mb(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Channel ch) -> { + var future = new CompletableFuture(); + Http2StreamChannel stream = new Http2StreamChannelBootstrap(ch).open().sync().getNow(); + stream.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) { + if (msg instanceof Http2DataFrame data) { + if (data.isEndStream()) + future.complete(null); + } else if (msg instanceof Http2HeadersFrame headers) { + if (headers.isEndStream()) + future.complete(null); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + future.completeExceptionally(cause); + } + }); + var headers = new DefaultHttp2Headers() + .method("GET") + .path("/get10mb") + .scheme("https") + .authority(BenchmarkSupport.H2_AUTHORITY); + stream.writeAndFlush(new DefaultHttp2HeadersFrame(headers, true)); + future.join(); + }, nettyChannel, counter); + + counter.logErrors("Netty H2 GET 10MB"); + } } diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2TinyRpcBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2TinyRpcBenchmark.java index bb6109c61f..8b62b57c07 100644 --- a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2TinyRpcBenchmark.java +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2TinyRpcBenchmark.java @@ -7,7 +7,6 @@ import java.io.InputStream; import java.io.OutputStream; -import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.time.Duration; import java.util.concurrent.ExecutorService; @@ -18,6 +17,7 @@ import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; @@ -29,17 +29,17 @@ import software.amazon.smithy.java.client.http.JavaHttpClientTransport; import software.amazon.smithy.java.context.Context; import software.amazon.smithy.java.http.api.HttpRequest; -import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; import software.amazon.smithy.java.io.datastream.DataStream; import software.amazon.smithy.java.io.uri.SmithyUri; /** - * Tiny request/response RPC latency benchmark over H2 for the JDK transport. + * Tiny request/response RPC latency benchmark over H2. * *

This uses JMH threads directly rather than the internal virtual-thread fanout so SampleTime * percentile output reflects per-request latency under real concurrent pressure. */ -@BenchmarkMode(org.openjdk.jmh.annotations.Mode.SampleTime) +@BenchmarkMode(Mode.SampleTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 2, time = 3) @Measurement(iterations = 3, time = 5) @@ -53,8 +53,8 @@ public class H2TinyRpcBenchmark { @Param({"4096"}) private int streamsPerConnection; - private HttpClient benchmarkClient; - private HttpClient javaClient; + private HttpClient smithyClient; + private java.net.http.HttpClient javaClient; private ExecutorService javaExecutor; private JavaHttpClientTransport javaTransport; private Context transportContext; @@ -64,14 +64,19 @@ public class H2TinyRpcBenchmark { public void setup() throws Exception { var sslContext = BenchmarkSupport.trustAllSsl(); - benchmarkClient = HttpClient.newBuilder() - .version(Version.HTTP_2) + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(connections) + .maxTotalConnections(connections) + .h2StreamsPerConnection(streamsPerConnection) + .h2InitialWindowSize(16 * 1024 * 1024) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_2) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(30)) + .dnsResolver(BenchmarkSupport.staticDns()) .build(); javaExecutor = Executors.newVirtualThreadPerTaskExecutor(); - javaClient = HttpClient.newBuilder() + javaClient = java.net.http.HttpClient.newBuilder() .version(Version.HTTP_2) .sslContext(sslContext) .executor(javaExecutor) @@ -79,11 +84,10 @@ public void setup() throws Exception { javaTransport = new JavaHttpClientTransport(javaClient); transportContext = Context.create(); - BenchmarkSupport.resetServer(benchmarkClient, BenchmarkSupport.H2_URL); + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H2_URL); smithyRequest = HttpRequest.create() .setUri(SmithyUri.of(BenchmarkSupport.H2_URL + "/rpc")) - .setHttpVersion(HttpVersion.HTTP_2) .setMethod("POST") .setBody(DataStream.ofBytes(BenchmarkSupport.POST_PAYLOAD)); } @@ -91,16 +95,17 @@ public void setup() throws Exception { @TearDown(Level.Trial) public void teardown() throws Exception { try { - if (benchmarkClient != null) { - String stats = BenchmarkSupport.getServerStats(benchmarkClient, BenchmarkSupport.H2_URL); + if (smithyClient != null) { + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H2_URL); System.out.println("H2 tiny RPC stats [conn=" + connections - + ", streams=" + streamsPerConnection + "]: " + stats); - System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(benchmarkClient)); + + ", streams=" + streamsPerConnection + + "]: " + stats); + System.out.println("H2 client stats: " + BenchmarkSupport.getH2ConnectionStats(smithyClient)); } } finally { - if (benchmarkClient != null) { - benchmarkClient.close(); - benchmarkClient = null; + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; } if (javaClient != null) { javaClient.close(); @@ -114,6 +119,14 @@ public void teardown() throws Exception { } } + @Benchmark + @Threads(64) + public void h2SmithyTinyRpc() throws Exception { + try (var response = smithyClient.send(smithyRequest)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + } + @Benchmark @Threads(64) public void h2JavaWrapperTinyRpc() throws Exception { diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cMixedGetPutBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cMixedGetPutBenchmark.java new file mode 100644 index 0000000000..ddbce5b4ab --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cMixedGetPutBenchmark.java @@ -0,0 +1,229 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.OutputStream; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import org.openjdk.jmh.annotations.AuxCounters; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.h2.ConnectionAgentH2cTransport; +import software.amazon.smithy.java.http.client.h2.EventLoopH2cTransport; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Mixed H2C benchmark that interleaves 1 MB GETs and 1 MB PUTs on the same client. + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@Warmup(iterations = 2, time = 3) +@Measurement(iterations = 3, time = 5) +@Fork(value = 1, jvmArgs = {"-Xms2g", "-Xmx2g"}) +@State(Scope.Benchmark) +public class H2cMixedGetPutBenchmark { + + /** Total requests issued per @Benchmark invocation; matched via @OperationsPerInvocation. */ + private static final int OPS = 1000; + + @Param({"1", "10"}) + private int concurrency; + + @Param({"1", "3"}) + private int connections; + + @Param({"4096"}) + private int streamsPerConnection; + + private HttpClient smithyClient; + private List eventLoopTransports; + private AtomicInteger eventLoopIndex; + private List agentTransports; + private AtomicInteger agentIndex; + private MixedRequests mixedRequests; + + @Setup(Level.Trial) + public void setup() throws Exception { + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(connections) + .maxTotalConnections(connections) + .h2StreamsPerConnection(streamsPerConnection) + .h2InitialWindowSize(16 * 1024 * 1024) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .dnsResolver(BenchmarkSupport.staticDns()) + .build(); + eventLoopTransports = new ArrayList<>(connections); + for (int i = 0; i < connections; i++) { + eventLoopTransports.add(new EventLoopH2cTransport(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2C_PORT)); + } + eventLoopIndex = new AtomicInteger(); + agentTransports = new ArrayList<>(connections); + for (int i = 0; i < connections; i++) { + agentTransports + .add(new ConnectionAgentH2cTransport(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2C_PORT)); + } + agentIndex = new AtomicInteger(); + + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H2C_URL); + + mixedRequests = new MixedRequests( + HttpRequest.create() + .setUri(SmithyUri.of(BenchmarkSupport.H2C_URL + "/getmb")) + .setHttpVersion(software.amazon.smithy.java.http.api.HttpVersion.HTTP_2) + .setMethod("GET"), + HttpRequest.create() + .setUri(SmithyUri.of(BenchmarkSupport.H2C_URL + "/putmb")) + .setHttpVersion(software.amazon.smithy.java.http.api.HttpVersion.HTTP_2) + .setMethod("PUT") + .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD))); + } + + @TearDown(Level.Trial) + public void teardown() throws Exception { + try { + if (smithyClient != null) { + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H2C_URL); + System.out.println("H2c mixed GET+PUT stats [c=" + concurrency + ", conn=" + connections + + ", streams=" + streamsPerConnection + "]: " + stats); + System.out.println("H2c client stats: " + BenchmarkSupport.getH2ConnectionStats(smithyClient)); + } + } finally { + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; + } + if (eventLoopTransports != null) { + for (var transport : eventLoopTransports) { + transport.close(); + } + eventLoopTransports = null; + eventLoopIndex = null; + } + if (agentTransports != null) { + for (var transport : agentTransports) { + transport.close(); + } + agentTransports = null; + agentIndex = null; + } + } + } + + @AuxCounters(AuxCounters.Type.EVENTS) + @State(Scope.Thread) + public static class Counter extends BenchmarkSupport.RequestCounter { + public long getRequests; + public long putRequests; + + @Setup(Level.Trial) + public void reset() { + super.reset(); + getRequests = 0; + putRequests = 0; + } + } + + private static final class MixedRequests { + private final HttpRequest getRequest; + private final HttpRequest putRequest; + private final AtomicInteger sequence = new AtomicInteger(); + private final AtomicLong totalGetRequests = new AtomicLong(); + private final AtomicLong totalPutRequests = new AtomicLong(); + + private MixedRequests(HttpRequest getRequest, HttpRequest putRequest) { + this.getRequest = getRequest; + this.putRequest = putRequest; + } + + private HttpRequest next() { + if ((sequence.getAndIncrement() & 1) == 0) { + totalGetRequests.incrementAndGet(); + return getRequest; + } + totalPutRequests.incrementAndGet(); + return putRequest; + } + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cSmithyMixedGetPutMb(Counter counter) throws InterruptedException { + long startGet = mixedRequests.totalGetRequests.get(); + long startPut = mixedRequests.totalPutRequests.get(); + BenchmarkSupport.runBenchmark(concurrency, OPS, (MixedRequests requests) -> { + var request = requests.next(); + try (var response = smithyClient.send(request)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, mixedRequests, counter); + counter.getRequests = mixedRequests.totalGetRequests.get() - startGet; + counter.putRequests = mixedRequests.totalPutRequests.get() - startPut; + + counter.logErrors("Smithy H2c mixed GET+PUT"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cEventLoopMixedGetPutMb(Counter counter) throws InterruptedException { + long startGet = mixedRequests.totalGetRequests.get(); + long startPut = mixedRequests.totalPutRequests.get(); + BenchmarkSupport.runBenchmark(concurrency, OPS, (MixedRequests requests) -> { + var request = requests.next(); + var transport = eventLoopTransports.get( + Math.floorMod(eventLoopIndex.getAndIncrement(), eventLoopTransports.size())); + try (var response = transport.send(request)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, mixedRequests, counter); + counter.getRequests = mixedRequests.totalGetRequests.get() - startGet; + counter.putRequests = mixedRequests.totalPutRequests.get() - startPut; + + counter.logErrors("EventLoop H2c mixed GET+PUT"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cConnectionAgentMixedGetPutMb(Counter counter) throws InterruptedException { + long startGet = mixedRequests.totalGetRequests.get(); + long startPut = mixedRequests.totalPutRequests.get(); + BenchmarkSupport.runBenchmark(concurrency, OPS, (MixedRequests requests) -> { + var request = requests.next(); + var transport = agentTransports.get(Math.floorMod(agentIndex.getAndIncrement(), agentTransports.size())); + try (var response = transport.send(request)) { + response.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, mixedRequests, counter); + counter.getRequests = mixedRequests.totalGetRequests.get() - startGet; + counter.putRequests = mixedRequests.totalPutRequests.get() - startPut; + + counter.logErrors("ConnectionAgent H2c mixed GET+PUT"); + } + +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cScalingBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cScalingBenchmark.java new file mode 100644 index 0000000000..f6eaa485b5 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/H2cScalingBenchmark.java @@ -0,0 +1,570 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import io.helidon.webclient.api.HttpClientResponse; +import io.helidon.webclient.http2.Http2Client; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.handler.codec.http2.Http2MultiplexHandler; +import io.netty.handler.codec.http2.Http2Settings; +import io.netty.handler.codec.http2.Http2StreamChannel; +import io.netty.handler.codec.http2.Http2StreamChannelBootstrap; +import io.netty.handler.codec.http2.Http2StreamFrame; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import org.openjdk.jmh.annotations.AuxCounters; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * HTTP/2 cleartext (h2c) client scaling benchmark. + * + *

For H2, the key parameters are: + *

    + *
  • concurrency - number of virtual threads making requests
  • + *
  • connections - number of H2 connections (each multiplexes many streams)
  • + *
  • streamsPerConnection - max concurrent streams per connection
  • + *
+ * + *

Effective parallelism ≈ connections × streamsPerConnection. + * Set concurrency higher to measure backpressure behavior. + * + *

Run with: ./gradlew :http:http-client:jmh -Pjmh.includes="H2cScalingBenchmark" + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@Warmup(iterations = 2, time = 3) +@Measurement(iterations = 3, time = 5) +@Fork(value = 1, jvmArgs = {"-Xms2g", "-Xmx2g", "-Xlog:gc*:stdout:time,level,tags"}) +@State(Scope.Benchmark) +public class H2cScalingBenchmark { + + /** Total requests issued per @Benchmark invocation; matched on each method via @OperationsPerInvocation. */ + private static final int OPS = 1000; + + @Param({"10"}) + private int concurrency; + + @Param({"1", "3", "5", "10"}) + private int connections; + + @Param({"100"}) + private int streamsPerConnection; + + private HttpClient smithyClient; + private Http2Client helidonClient; + + // Netty client state - multiple connections like Smithy + private EventLoopGroup nettyGroup; + private List nettyChannels; + private List nettyStreamBootstraps; + private AtomicInteger smithyConnectionCount; + + @Setup(Level.Trial) + public void setupIteration() throws Exception { + closeClients(); + + System.out.println("H2c setup: concurrency=" + concurrency + + ", connections=" + connections + + ", streams=" + streamsPerConnection); + + smithyConnectionCount = new AtomicInteger(0); + + // Smithy H2c client. The epoll transport is used automatically when the native library is + // available (Linux); otherwise the NIO socket path is used. + smithyClient = HttpClient.builder() + .maxConnectionsPerRoute(connections) + .maxTotalConnections(connections) + .h2StreamsPerConnection(streamsPerConnection) + .h2InitialWindowSize(1024 * 1024) + .maxIdleTime(Duration.ofMinutes(2)) + .httpVersionPolicy(HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) + .dnsResolver(BenchmarkSupport.staticDns()) + .addListener(new HttpClientListener() { + @Override + public void onConnectionCreated(HttpConnection conn) { + int count = smithyConnectionCount.incrementAndGet(); + System.out.println(" [Smithy] New connection #" + count + ": " + conn); + } + }) + .build(); + + // Helidon H2c client + helidonClient = Http2Client.builder() + .baseUri(BenchmarkSupport.H2C_URL) + .shareConnectionCache(false) + .protocolConfig(pc -> pc.priorKnowledge(true)) + .build(); + + // Netty H2c client - create same number of connections as Smithy + nettyGroup = new NioEventLoopGroup(); + nettyChannels = new ArrayList<>(); + nettyStreamBootstraps = new ArrayList<>(); + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(nettyGroup) + .channel(NioSocketChannel.class) + .option(ChannelOption.SO_KEEPALIVE, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline() + .addLast( + Http2FrameCodecBuilder.forClient() + .initialSettings( + Http2Settings.defaultSettings() + .maxConcurrentStreams(100000) + .initialWindowSize(1024 * 1024)) + .build(), + new Http2MultiplexHandler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0( + ChannelHandlerContext ctx, + Http2StreamFrame msg + ) {} + })); + } + }); + for (int i = 0; i < connections; i++) { + Channel ch = + bootstrap.connect(new InetSocketAddress(BenchmarkSupport.BENCH_HOST, BenchmarkSupport.H2C_PORT)) + .sync() + .channel(); + nettyChannels.add(ch); + nettyStreamBootstraps.add(new Http2StreamChannelBootstrap(ch)); + } + + BenchmarkSupport.resetServer(smithyClient, BenchmarkSupport.H2C_URL); + } + + @TearDown(Level.Trial) + public void teardown() throws Exception { + String stats = BenchmarkSupport.getServerStats(smithyClient, BenchmarkSupport.H2C_URL); + System.out.println("H2c stats [c=" + concurrency + ", conn=" + connections + + ", streams=" + streamsPerConnection + "]: " + stats); + closeClients(); + } + + private void closeClients() throws Exception { + if (smithyClient != null) { + smithyClient.close(); + smithyClient = null; + } + if (helidonClient != null) { + helidonClient.closeResource(); + helidonClient = null; + } + if (nettyChannels != null) { + for (Channel ch : nettyChannels) { + ch.close().sync(); + } + nettyChannels = null; + nettyStreamBootstraps = null; + } + if (nettyGroup != null) { + nettyGroup.shutdownGracefully().sync(); + nettyGroup = null; + } + } + + @AuxCounters(AuxCounters.Type.EVENTS) + @State(Scope.Thread) + public static class Counter extends BenchmarkSupport.RequestCounter { + @Setup(Level.Iteration) + public void reset() { + super.reset(); + } + + // Override getters so JMH annotation processor sees them directly + @Override + public long requests() { + return requests; + } + + @Override + public long errors() { + return errors; + } + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cSmithyGet(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2C_URL + "/get"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().discard(); + } + }, request, counter); + + counter.logErrors("Smithy H2c"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cHelidonGet(Counter counter) throws InterruptedException { + BenchmarkSupport.runBenchmark(concurrency, OPS, (Http2Client client) -> { + try (HttpClientResponse response = client.get("/get").request()) { + response.entity().consume(); + } + }, helidonClient, counter); + + counter.logErrors("Helidon H2c"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cSmithyPost(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2C_URL + "/post"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("POST") + .setBody(DataStream.ofBytes(BenchmarkSupport.POST_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2c POST"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cSmithyPutMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2C_URL + "/putmb"); + var request = HttpRequest.create() + .setUri(uri) + .setMethod("PUT") + .setBody(DataStream.ofBytes(BenchmarkSupport.MB_PAYLOAD)); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2c PUT 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cSmithyGetMb(Counter counter) throws InterruptedException { + var uri = SmithyUri.of(BenchmarkSupport.H2C_URL + "/getmb"); + var request = HttpRequest.create().setUri(uri).setMethod("GET"); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (HttpRequest req) -> { + try (var res = smithyClient.send(req)) { + res.body().asInputStream().transferTo(OutputStream.nullOutputStream()); + } + }, request, counter); + + counter.logErrors("Smithy H2c GET 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cNettyGet(Counter counter) throws Exception { + DefaultHttp2Headers headers = new DefaultHttp2Headers(); + headers.method("GET"); + headers.path("/get"); + headers.scheme("http"); + headers.authority(BenchmarkSupport.H2C_AUTHORITY); + + var connectionIndex = new AtomicInteger(0); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (DefaultHttp2Headers h) -> { + var latch = new CountDownLatch(1); + var error = new AtomicReference(); + + int idx = connectionIndex.getAndIncrement() % nettyStreamBootstraps.size(); + nettyStreamBootstraps.get(idx).open().addListener(future -> { + if (!future.isSuccess()) { + error.set(future.cause()); + latch.countDown(); + return; + } + + Http2StreamChannel streamChannel = (Http2StreamChannel) future.get(); + streamChannel.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame frame) { + if (frame instanceof Http2DataFrame df) { + df.content().skipBytes(df.content().readableBytes()); + } + boolean endStream = (frame instanceof Http2HeadersFrame hf && hf.isEndStream()) + || (frame instanceof Http2DataFrame df2 && df2.isEndStream()); + if (endStream) { + ctx.close(); + latch.countDown(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + error.set(cause); + ctx.close(); + latch.countDown(); + } + }); + + streamChannel.writeAndFlush(new DefaultHttp2HeadersFrame(h, true)); + }); + + latch.await(); + if (error.get() != null) { + throw new RuntimeException(error.get()); + } + }, headers, counter); + + counter.logErrors("Netty H2c GET"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cNettyGetMb(Counter counter) throws Exception { + DefaultHttp2Headers headers = new DefaultHttp2Headers(); + headers.method("GET"); + headers.path("/getmb"); + headers.scheme("http"); + headers.authority(BenchmarkSupport.H2C_AUTHORITY); + + var connectionIndex = new AtomicInteger(0); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (DefaultHttp2Headers h) -> { + var latch = new CountDownLatch(1); + var error = new AtomicReference(); + + int idx = connectionIndex.getAndIncrement() % nettyStreamBootstraps.size(); + nettyStreamBootstraps.get(idx).open().addListener(future -> { + if (!future.isSuccess()) { + error.set(future.cause()); + latch.countDown(); + return; + } + + Http2StreamChannel streamChannel = (Http2StreamChannel) future.get(); + streamChannel.pipeline().addLast(new SimpleChannelInboundHandler() { + private final byte[] copyBuf = new byte[8192]; + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame frame) { + if (frame instanceof Http2DataFrame df) { + // Copy data like Smithy does, not just skip + var buf = df.content(); + while (buf.readableBytes() > 0) { + int toRead = Math.min(buf.readableBytes(), copyBuf.length); + buf.readBytes(copyBuf, 0, toRead); + } + } + boolean endStream = (frame instanceof Http2HeadersFrame hf && hf.isEndStream()) + || (frame instanceof Http2DataFrame df2 && df2.isEndStream()); + if (endStream) { + ctx.close(); + latch.countDown(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + error.set(cause); + ctx.close(); + latch.countDown(); + } + }); + + streamChannel.writeAndFlush(new DefaultHttp2HeadersFrame(h, true)); + }); + + latch.await(); + if (error.get() != null) { + throw new RuntimeException(error.get()); + } + }, headers, counter); + + counter.logErrors("Netty H2c GET 1MB"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cNettyPost(Counter counter) throws Exception { + DefaultHttp2Headers headers = new DefaultHttp2Headers(); + headers.method("POST"); + headers.path("/post"); + headers.scheme("http"); + headers.authority(BenchmarkSupport.H2C_AUTHORITY); + headers.setInt("content-length", BenchmarkSupport.POST_PAYLOAD.length); + + var connectionIndex = new AtomicInteger(0); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (DefaultHttp2Headers h) -> { + var latch = new CountDownLatch(1); + var error = new AtomicReference(); + + int idx = connectionIndex.getAndIncrement() % nettyStreamBootstraps.size(); + nettyStreamBootstraps.get(idx).open().addListener(future -> { + if (!future.isSuccess()) { + error.set(future.cause()); + latch.countDown(); + return; + } + + Http2StreamChannel streamChannel = (Http2StreamChannel) future.get(); + streamChannel.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame frame) { + if (frame instanceof Http2DataFrame df) { + df.content().skipBytes(df.content().readableBytes()); + } + boolean endStream = (frame instanceof Http2HeadersFrame hf && hf.isEndStream()) + || (frame instanceof Http2DataFrame df2 && df2.isEndStream()); + if (endStream) { + ctx.close(); + latch.countDown(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + error.set(cause); + ctx.close(); + latch.countDown(); + } + }); + + // Send headers (endStream=false since we have a body) + streamChannel.write(new DefaultHttp2HeadersFrame(h, false)); + // Send body with endStream=true + streamChannel.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(BenchmarkSupport.POST_PAYLOAD), + true)); + }); + + latch.await(); + if (error.get() != null) { + throw new RuntimeException(error.get()); + } + }, headers, counter); + + counter.logErrors("Netty H2c POST"); + } + + @Benchmark + @OperationsPerInvocation(OPS) + @Threads(1) + public void h2cNettyPutMb(Counter counter) throws Exception { + DefaultHttp2Headers headers = new DefaultHttp2Headers(); + headers.method("PUT"); + headers.path("/putmb"); + headers.scheme("http"); + headers.authority(BenchmarkSupport.H2C_AUTHORITY); + headers.setInt("content-length", BenchmarkSupport.MB_PAYLOAD.length); + + var connectionIndex = new AtomicInteger(0); + + BenchmarkSupport.runBenchmark(concurrency, OPS, (DefaultHttp2Headers h) -> { + var latch = new CountDownLatch(1); + var error = new AtomicReference(); + + int idx = connectionIndex.getAndIncrement() % nettyStreamBootstraps.size(); + nettyStreamBootstraps.get(idx).open().addListener(future -> { + if (!future.isSuccess()) { + error.set(future.cause()); + latch.countDown(); + return; + } + + Http2StreamChannel streamChannel = (Http2StreamChannel) future.get(); + streamChannel.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame frame) { + if (frame instanceof Http2DataFrame df) { + df.content().skipBytes(df.content().readableBytes()); + } + boolean endStream = (frame instanceof Http2HeadersFrame hf && hf.isEndStream()) + || (frame instanceof Http2DataFrame df2 && df2.isEndStream()); + if (endStream) { + ctx.close(); + latch.countDown(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + error.set(cause); + ctx.close(); + latch.countDown(); + } + }); + + // Send headers (endStream=false since we have a body) + streamChannel.write(new DefaultHttp2HeadersFrame(h, false)); + // Send body with endStream=true + streamChannel.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.wrappedBuffer(BenchmarkSupport.MB_PAYLOAD), + true)); + }); + + latch.await(); + if (error.get() != null) { + throw new RuntimeException(error.get()); + } + }, headers, counter); + + counter.logErrors("Netty H2c PUT 1MB"); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/NettyH2Transport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/NettyH2Transport.java new file mode 100644 index 0000000000..9e7acf39cb --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/NettyH2Transport.java @@ -0,0 +1,384 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.WriteBufferWaterMark; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http2.DefaultHttp2DataFrame; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2Headers; +import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.handler.codec.http2.Http2MultiplexHandler; +import io.netty.handler.codec.http2.Http2SecurityUtil; +import io.netty.handler.codec.http2.Http2Settings; +import io.netty.handler.codec.http2.Http2StreamChannel; +import io.netty.handler.codec.http2.Http2StreamChannelBootstrap; +import io.netty.handler.codec.http2.Http2StreamFrame; +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.ApplicationProtocolNames; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SupportedCipherSuiteFilter; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.LockSupport; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Netty-backed HTTP/2 transport that exposes blocking {@code send(HttpRequest)} and streams + * request body uploads and response body downloads. + * + *

Streaming behavior: + *

    + *
  • Request body: Caller VT reads chunks from {@code request.body().asInputStream()} + * and writes each chunk to the stream channel. Respects {@code channel.isWritable()} for + * backpressure — VT parks when the outbound buffer is full.
  • + *
  • Response body: Returned as a {@link DataStream} wrapping a blocking + * {@link InputStream} that pulls from a bounded queue fed by the Netty handler. Headers + * are returned to the caller as soon as the response HEADERS frame arrives; body bytes + * stream as they arrive.
  • + *
+ */ +final class NettyH2Transport implements AutoCloseable { + + // Chunk size for streamed uploads. + private static final int UPLOAD_CHUNK = 64 * 1024; + // Queue depth for response body chunks (backpressure: reader-side). + private static final int RESPONSE_QUEUE_CAPACITY = 64; + // Marker in response queue to signal end-of-stream. + private static final ByteBuf EOS_MARKER = Unpooled.EMPTY_BUFFER; + + private final EventLoopGroup group; + private final Channel channel; + + NettyH2Transport(String host, int port) throws Exception { + this.group = new NioEventLoopGroup(1); + + SslContext sslCtx = SslContextBuilder.forClient() + .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2)) + .build(); + + var frameCodec = Http2FrameCodecBuilder.forClient() + .initialSettings(Http2Settings.defaultSettings() + .initialWindowSize(16 * 1024 * 1024) + .maxConcurrentStreams(4096)) + .build(); + + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + // Standard watermarks for backpressure signaling via isWritable(). + .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(32 * 1024, 256 * 1024)) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast(sslCtx.newHandler(ch.alloc(), host, port)); + ch.pipeline().addLast(frameCodec); + ch.pipeline().addLast(new Http2MultiplexHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ignored) {} + })); + } + }); + + this.channel = b.connect(host, port).sync().channel(); + } + + HttpResponse send(HttpRequest request) throws IOException { + Http2StreamChannel stream; + try { + stream = new Http2StreamChannelBootstrap(channel).open().sync().getNow(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted opening H2 stream", e); + } + + CompletableFuture headersFuture = new CompletableFuture<>(); + LinkedBlockingQueue bodyQueue = new LinkedBlockingQueue<>(RESPONSE_QUEUE_CAPACITY); + ResponseHandler responseHandler = new ResponseHandler(headersFuture, bodyQueue); + stream.pipeline().addLast(responseHandler); + + Http2Headers nettyHeaders = toNettyHeaders(request); + boolean hasBody = request.body() != null && request.body().contentLength() != 0; + + // Submit headers on the event loop. For bodyless requests, this also closes the stream. + stream.eventLoop().execute(() -> { + stream.write(new DefaultHttp2HeadersFrame(nettyHeaders, !hasBody)); + if (!hasBody) { + stream.flush(); + } + }); + + // Stream the request body (on caller VT) if present, respecting backpressure. + if (hasBody) { + try (InputStream in = request.body().asInputStream()) { + streamRequestBody(stream, in); + } catch (IOException e) { + stream.close(); + throw e; + } + } + + // Wait for headers (not the whole body). + HttpResponse headResponse; + try { + headResponse = headersFuture.get(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for response headers", e); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException io) + throw io; + throw new IOException("Request failed", cause); + } catch (TimeoutException e) { + throw new IOException("Request timed out waiting for headers", e); + } + + // Replace the body with a streaming InputStream pulling from the queue. + var bodyStream = new ResponseBodyInputStream(bodyQueue, responseHandler); + return headResponse.toModifiable().setBody(DataStream.ofInputStream(bodyStream)).toUnmodifiable(); + } + + /** + * Read the request body in chunks and write to the stream channel. Blocks the VT on + * backpressure (channel not writable). + */ + private void streamRequestBody(Http2StreamChannel stream, InputStream in) throws IOException { + byte[] buf = new byte[UPLOAD_CHUNK]; + while (true) { + int n = in.read(buf); + if (n < 0) { + // End-of-stream: send empty DATA with endStream=true + stream.eventLoop() + .execute(() -> stream.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true))); + return; + } + if (n == 0) + continue; + + // Backpressure: park until the channel is writable again. + while (!stream.isWritable()) { + LockSupport.parkNanos(100_000); // 100us hint - parkNanos handles spurious fine + if (!stream.isOpen()) { + throw new IOException("Stream closed while waiting for writability"); + } + } + + // Allocate a direct pooled buffer from the channel's allocator and copy chunk in. + ByteBuf out = stream.alloc().buffer(n); + out.writeBytes(buf, 0, n); + stream.eventLoop().execute(() -> stream.writeAndFlush(new DefaultHttp2DataFrame(out, false))); + } + } + + private static Http2Headers toNettyHeaders(HttpRequest request) { + var uri = request.uri(); + String path = uri.getPath(); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + path = path + "?" + uri.getQuery(); + } + var headers = new DefaultHttp2Headers() + .method(request.method()) + .path(path) + .scheme(uri.getScheme()) + .authority(uri.getHost() + (uri.getPort() > 0 ? ":" + uri.getPort() : "")); + for (Map.Entry> e : request.headers().map().entrySet()) { + String name = e.getKey().toLowerCase(Locale.ROOT); + for (String v : e.getValue()) { + headers.add(name, v); + } + } + return headers; + } + + @Override + public void close() { + try { + channel.close().sync(); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + group.shutdownGracefully(); + } + + /** + * Completes {@code headersFuture} as soon as HEADERS arrives. DATA frames are pushed onto + * {@code bodyQueue}. An EOS marker is enqueued when the stream ends. + */ + private static final class ResponseHandler extends SimpleChannelInboundHandler { + private final CompletableFuture headersFuture; + private final LinkedBlockingQueue bodyQueue; + private int status; + volatile Throwable error; + + ResponseHandler(CompletableFuture headersFuture, LinkedBlockingQueue bodyQueue) { + this.headersFuture = headersFuture; + this.bodyQueue = bodyQueue; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Http2StreamFrame msg) throws Exception { + if (msg instanceof Http2HeadersFrame hf) { + var s = hf.headers().status(); + if (s != null) { + status = Integer.parseInt(s.toString()); + } + var response = HttpResponse.create() + .setHttpVersion(HttpVersion.HTTP_2) + .setStatusCode(status) + .setHeaders(HttpHeaders.ofModifiable()) + .setBody(DataStream.ofEmpty()); // replaced by send() + headersFuture.complete(response); + if (hf.isEndStream()) { + bodyQueue.put(EOS_MARKER); + } + } else if (msg instanceof Http2DataFrame df) { + ByteBuf content = df.content(); + if (content.readableBytes() > 0) { + bodyQueue.put(content.retain()); + } + if (df.isEndStream()) { + bodyQueue.put(EOS_MARKER); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + error = cause; + if (!headersFuture.isDone()) { + headersFuture.completeExceptionally(cause); + } + try { + bodyQueue.put(EOS_MARKER); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + ctx.close(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + try { + bodyQueue.put(EOS_MARKER); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + /** + * Blocking InputStream that pulls {@link ByteBuf} chunks from the handler's queue. + * Releases each chunk as it's consumed. + */ + private static final class ResponseBodyInputStream extends InputStream { + private final LinkedBlockingQueue queue; + private final ResponseHandler handler; + private ByteBuf current; + private boolean done; + + ResponseBodyInputStream(LinkedBlockingQueue queue, ResponseHandler handler) { + this.queue = queue; + this.handler = handler; + } + + private boolean ensure() throws IOException { + while (current == null || !current.isReadable()) { + releaseCurrent(); + if (done) + return false; + try { + ByteBuf next = queue.take(); + if (next == EOS_MARKER) { + done = true; + if (handler.error != null) { + throw new IOException("Response stream failed", handler.error); + } + return false; + } + current = next; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted reading response body", e); + } + } + return true; + } + + private void releaseCurrent() { + if (current != null) { + current.release(); + current = null; + } + } + + @Override + public int read() throws IOException { + if (!ensure()) + return -1; + return current.readByte() & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (!ensure()) + return -1; + int n = Math.min(len, current.readableBytes()); + current.readBytes(b, off, n); + return n; + } + + @Override + public void close() { + releaseCurrent(); + while (!done) { + ByteBuf next = queue.poll(); + if (next == null) + break; + if (next == EOS_MARKER) { + done = true; + } else { + next.release(); + } + } + } + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Constants.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Constants.java new file mode 100644 index 0000000000..d06582015c --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Constants.java @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.nio.charset.StandardCharsets; + +/** + * Benchmark transport copy of the production H2 constants so the connection-agent branch can port + * production protocol logic without taking a dependency on package-private implementation classes. + */ +final class ConnectionAgentH2Constants { + + private ConnectionAgentH2Constants() {} + + static final byte[] CONNECTION_PREFACE = + "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.US_ASCII); + + static final int FRAME_HEADER_SIZE = 9; + + static final int FRAME_TYPE_DATA = 0x0; + static final int FRAME_TYPE_HEADERS = 0x1; + static final int FRAME_TYPE_RST_STREAM = 0x3; + static final int FRAME_TYPE_SETTINGS = 0x4; + static final int FRAME_TYPE_PING = 0x6; + static final int FRAME_TYPE_GOAWAY = 0x7; + static final int FRAME_TYPE_WINDOW_UPDATE = 0x8; + + static final int FLAG_END_STREAM = 0x1; + static final int FLAG_END_HEADERS = 0x4; + static final int FLAG_ACK = 0x1; + + static final int DEFAULT_INITIAL_WINDOW_SIZE = 65535; + static final int DEFAULT_MAX_FRAME_SIZE = 16384; + + static final String PSEUDO_METHOD = ":method"; + static final String PSEUDO_SCHEME = ":scheme"; + static final String PSEUDO_AUTHORITY = ":authority"; + static final String PSEUDO_PATH = ":path"; + static final String PSEUDO_STATUS = ":status"; + + static String frameTypeName(int type) { + return switch (type) { + case FRAME_TYPE_DATA -> "DATA"; + case FRAME_TYPE_HEADERS -> "HEADERS"; + case FRAME_TYPE_RST_STREAM -> "RST_STREAM"; + case FRAME_TYPE_SETTINGS -> "SETTINGS"; + case FRAME_TYPE_PING -> "PING"; + case FRAME_TYPE_GOAWAY -> "GOAWAY"; + case FRAME_TYPE_WINDOW_UPDATE -> "WINDOW_UPDATE"; + default -> "UNKNOWN(" + type + ")"; + }; + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Exception.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Exception.java new file mode 100644 index 0000000000..eb83dca3f0 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2Exception.java @@ -0,0 +1,34 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; + +final class ConnectionAgentH2Exception extends IOException { + + private final int errorCode; + private final int streamId; + + ConnectionAgentH2Exception(int errorCode, String message) { + super(message + " (" + errorCode + ")"); + this.errorCode = errorCode; + this.streamId = 0; + } + + ConnectionAgentH2Exception(int errorCode, int streamId, String message) { + super("Stream " + streamId + ": " + message + " (" + errorCode + ")"); + this.errorCode = errorCode; + this.streamId = streamId; + } + + int errorCode() { + return errorCode; + } + + int streamId() { + return streamId; + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2FrameOps.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2FrameOps.java new file mode 100644 index 0000000000..dd8dd98c2d --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2FrameOps.java @@ -0,0 +1,66 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +final class ConnectionAgentH2FrameOps { + + private ConnectionAgentH2FrameOps() {} + + static void validateFrameSize(int type, int flags, int length) throws ConnectionAgentH2Exception { + switch (type) { + case ConnectionAgentH2Constants.FRAME_TYPE_PING: + if (length != 8) { + throw new ConnectionAgentH2Exception(0x6, "PING frame must have 8-byte payload, got " + length); + } + break; + case ConnectionAgentH2Constants.FRAME_TYPE_SETTINGS: + if ((flags & ConnectionAgentH2Constants.FLAG_ACK) != 0 && length != 0) { + throw new ConnectionAgentH2Exception(0x6, + "SETTINGS ACK frame must have empty payload, got " + length); + } + break; + case ConnectionAgentH2Constants.FRAME_TYPE_WINDOW_UPDATE: + case ConnectionAgentH2Constants.FRAME_TYPE_RST_STREAM: + if (length != 4) { + throw new ConnectionAgentH2Exception(0x6, + ConnectionAgentH2Constants.frameTypeName(type) + + " frame must have 4-byte payload, got " + length); + } + break; + case ConnectionAgentH2Constants.FRAME_TYPE_GOAWAY: + if (length < 8) { + throw new ConnectionAgentH2Exception(0x6, + "GOAWAY frame must have at least 8-byte payload, got " + length); + } + break; + default: + break; + } + } + + static void validateStreamId(int type, int streamId) throws ConnectionAgentH2Exception { + switch (type) { + case ConnectionAgentH2Constants.FRAME_TYPE_DATA: + case ConnectionAgentH2Constants.FRAME_TYPE_HEADERS: + case ConnectionAgentH2Constants.FRAME_TYPE_RST_STREAM: + if (streamId == 0) { + throw new ConnectionAgentH2Exception(0x1, + ConnectionAgentH2Constants.frameTypeName(type) + " frame must have non-zero stream ID"); + } + break; + case ConnectionAgentH2Constants.FRAME_TYPE_SETTINGS: + case ConnectionAgentH2Constants.FRAME_TYPE_PING: + case ConnectionAgentH2Constants.FRAME_TYPE_GOAWAY: + if (streamId != 0) { + throw new ConnectionAgentH2Exception(0x1, + ConnectionAgentH2Constants.frameTypeName(type) + " frame must have stream ID 0"); + } + break; + default: + break; + } + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2StreamState.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2StreamState.java new file mode 100644 index 0000000000..49d6da0bc5 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2StreamState.java @@ -0,0 +1,174 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +/** + * Port of the production H2 packed stream state for the connection-agent experiment. + */ +final class ConnectionAgentH2StreamState { + + private static final int MASK_STATUS_CODE = 0x3FF; + private static final int FLAG_HEADERS_RECEIVED = 1 << 10; + private static final int FLAG_END_STREAM_RX = 1 << 11; + private static final int FLAG_END_STREAM_TX = 1 << 12; + + private static final int SHIFT_READ_STATE = 13; + private static final int MASK_READ_STATE = 0x7 << SHIFT_READ_STATE; + + private static final int SHIFT_STREAM_STATE = 16; + private static final int MASK_STREAM_STATE = 0xF << SHIFT_STREAM_STATE; + + static final int RS_WAITING = 0; + static final int RS_READING = 1; + static final int RS_DONE = 2; + static final int RS_ERROR = 3; + + static final int SS_IDLE = 0; + static final int SS_OPEN = 1; + static final int SS_HALF_CLOSED_LOCAL = 2; + static final int SS_HALF_CLOSED_REMOTE = 3; + static final int SS_CLOSED = 4; + + private static final VarHandle STATE_HANDLE; + + static { + try { + STATE_HANDLE = MethodHandles.lookup() + .findVarHandle(ConnectionAgentH2StreamState.class, "packedState", int.class); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + @SuppressWarnings("FieldMayBeFinal") + private volatile int packedState = (SS_IDLE << SHIFT_STREAM_STATE) | (RS_WAITING << SHIFT_READ_STATE); + + int getStatusCode() { + int code = packedState & MASK_STATUS_CODE; + return code == 0 ? -1 : code; + } + + boolean isResponseHeadersReceived() { + return (packedState & FLAG_HEADERS_RECEIVED) != 0; + } + + boolean isEndStreamReceived() { + return (packedState & FLAG_END_STREAM_RX) != 0; + } + + boolean isEndStreamSent() { + return (packedState & FLAG_END_STREAM_TX) != 0; + } + + void onHeadersEncoded(boolean endStream) { + for (;;) { + int current = packedState; + int next = current; + if (endStream) { + next |= FLAG_END_STREAM_TX; + next &= ~MASK_STREAM_STATE; + next |= (SS_HALF_CLOSED_LOCAL << SHIFT_STREAM_STATE); + } else { + next &= ~MASK_STREAM_STATE; + next |= (SS_OPEN << SHIFT_STREAM_STATE); + } + if (STATE_HANDLE.compareAndSet(this, current, next)) { + return; + } + } + } + + void setResponseHeadersReceived(int statusCode) { + for (;;) { + int current = packedState; + int next = current; + next &= ~MASK_STATUS_CODE; + next |= (statusCode & MASK_STATUS_CODE); + next |= FLAG_HEADERS_RECEIVED; + int readState = (current & MASK_READ_STATE) >> SHIFT_READ_STATE; + if (readState == RS_WAITING) { + next &= ~MASK_READ_STATE; + next |= (RS_READING << SHIFT_READ_STATE); + } + if (STATE_HANDLE.compareAndSet(this, current, next)) { + return; + } + } + } + + void markEndStreamReceived() { + for (;;) { + int current = packedState; + int next = current | FLAG_END_STREAM_RX; + next &= ~MASK_READ_STATE; + next |= (RS_DONE << SHIFT_READ_STATE); + int currentStreamState = (current & MASK_STREAM_STATE) >> SHIFT_STREAM_STATE; + int nextStreamState = computeEndStreamTransition(currentStreamState, true); + if (nextStreamState >= 0) { + next &= ~MASK_STREAM_STATE; + next |= (nextStreamState << SHIFT_STREAM_STATE); + } + if (STATE_HANDLE.compareAndSet(this, current, next)) { + return; + } + } + } + + void markEndStreamSent() { + for (;;) { + int current = packedState; + if ((current & FLAG_END_STREAM_TX) != 0) { + return; + } + int next = current | FLAG_END_STREAM_TX; + int currentStreamState = (current & MASK_STREAM_STATE) >> SHIFT_STREAM_STATE; + int nextStreamState = computeEndStreamTransition(currentStreamState, false); + if (nextStreamState >= 0) { + next &= ~MASK_STREAM_STATE; + next |= (nextStreamState << SHIFT_STREAM_STATE); + } + if (STATE_HANDLE.compareAndSet(this, current, next)) { + return; + } + } + } + + void setErrorState() { + setEndStreamFlagAndReadState(RS_ERROR); + } + + private void setEndStreamFlagAndReadState(int readState) { + for (;;) { + int current = packedState; + int next = current | FLAG_END_STREAM_RX; + next &= ~MASK_READ_STATE; + next |= (readState << SHIFT_READ_STATE); + if (STATE_HANDLE.compareAndSet(this, current, next)) { + return; + } + } + } + + private static int computeEndStreamTransition(int currentStreamState, boolean isReceived) { + if (isReceived) { + if (currentStreamState == SS_OPEN) { + return SS_HALF_CLOSED_REMOTE; + } else if (currentStreamState == SS_HALF_CLOSED_LOCAL) { + return SS_CLOSED; + } + } else { + if (currentStreamState == SS_OPEN) { + return SS_HALF_CLOSED_LOCAL; + } else if (currentStreamState == SS_HALF_CLOSED_REMOTE) { + return SS_CLOSED; + } + } + return -1; + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2cTransport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2cTransport.java new file mode 100644 index 0000000000..b2d644ea48 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/ConnectionAgentH2cTransport.java @@ -0,0 +1,767 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Benchmark-only H2C transport with a single virtual-thread connection owner and passive per-stream + * state objects. The connection agent owns all socket I/O and H2 state, while callers block on + * stream-local response bodies. + */ +public final class ConnectionAgentH2cTransport implements AutoCloseable { + + private static final int TARGET_CONNECTION_WINDOW = 16 * 1024 * 1024; + private static final int WRITE_SCRATCH_SIZE = 256 * 1024; + private static final ByteBuffer END_OF_STREAM = ByteBuffer.allocate(0); + + private final Thread connectionThread; + private final Selector selector; + private final SocketChannel channel; + private final SelectionKey selectionKey; + private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>(); + + // Connection-thread only state. + private final HpackEncoder encoder = new HpackEncoder(); + private final HpackDecoder decoder = new HpackDecoder(); + private final ByteBuffer readScratch = ByteBuffer.allocateDirect(1 << 17); + private final ByteBuffer writeScratch = ByteBuffer.allocateDirect(WRITE_SCRATCH_SIZE); + private final Map streams = new HashMap<>(); + private final ArrayDeque unsentBodyStreams = new ArrayDeque<>(); + private int nextStreamId = 1; + private int sendWindow = ConnectionAgentH2Constants.DEFAULT_INITIAL_WINDOW_SIZE; + private int recvWindow = TARGET_CONNECTION_WINDOW; + private int remoteInitialWindow = ConnectionAgentH2Constants.DEFAULT_INITIAL_WINDOW_SIZE; + private int remoteMaxFrame = ConnectionAgentH2Constants.DEFAULT_MAX_FRAME_SIZE; + + private int frameHdrBytes; + private final byte[] frameHdrBuf = new byte[ConnectionAgentH2Constants.FRAME_HEADER_SIZE]; + private int curPayloadLen; + private int curType; + private int curFlags; + private int curStreamId; + private int curPayloadRead; + private byte[] curStaged; + private boolean headerParsed; + private byte[] copyScratch = new byte[8192]; + + private static final class StreamState { + final int streamId; + final CompletableFuture responseFuture; + final StreamBody body; + final ConnectionAgentH2StreamState state = new ConnectionAgentH2StreamState(); + int sendWindow; + ByteBuffer pendingRequestBody; + + StreamState(int streamId, int sendWindow, CompletableFuture responseFuture) { + this.streamId = streamId; + this.sendWindow = sendWindow; + this.responseFuture = responseFuture; + this.body = new StreamBody(); + } + } + + private static final class StreamBody implements DataStream { + private final ChunkRing chunks = new ChunkRing(); + private volatile boolean consumed; + + @Override + public long contentLength() { + return -1; + } + + @Override + public String contentType() { + return null; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return !consumed; + } + + @Override + public InputStream asInputStream() { + if (consumed) { + throw new IllegalStateException("Response body is not replayable and has already been consumed"); + } + consumed = true; + return new StreamBodyInputStream(chunks); + } + + @Override + public void close() { + chunks.finish(); + } + + void enqueue(byte[] bytes, int length) { + if (length == 0) { + return; + } + chunks.offer(ByteBuffer.wrap(bytes, 0, length)); + } + + void fail(Throwable throwable) { + chunks.fail(throwable); + } + + void complete() { + chunks.finish(); + } + } + + private static final class ChunkRing { + private ByteBuffer[] ring = new ByteBuffer[32]; + private int head; + private int tail; + private int size; + private Throwable failure; + private boolean finished; + + synchronized void offer(ByteBuffer buffer) { + if (finished || failure != null) { + return; + } + if (size == ring.length) { + grow(); + } + ring[tail] = buffer; + tail = (tail + 1) & (ring.length - 1); + size++; + notifyAll(); + } + + synchronized ByteBuffer take() throws IOException { + while (size == 0 && failure == null && !finished) { + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for response body data", e); + } + } + if (failure != null) { + if (failure instanceof IOException ioe) { + throw ioe; + } + throw new IOException("Response body failed", failure); + } + if (size == 0) { + return END_OF_STREAM; + } + ByteBuffer result = ring[head]; + ring[head] = null; + head = (head + 1) & (ring.length - 1); + size--; + return result; + } + + synchronized void finish() { + finished = true; + notifyAll(); + } + + synchronized void fail(Throwable throwable) { + failure = throwable; + notifyAll(); + } + + private void grow() { + ByteBuffer[] next = new ByteBuffer[ring.length << 1]; + for (int i = 0; i < size; i++) { + next[i] = ring[(head + i) & (ring.length - 1)]; + } + ring = next; + head = 0; + tail = size; + } + } + + private static final class StreamBodyInputStream extends InputStream { + private final ChunkRing chunks; + private ByteBuffer current; + private boolean eof; + + private StreamBodyInputStream(ChunkRing chunks) { + this.chunks = chunks; + } + + @Override + public int read() throws IOException { + byte[] single = new byte[1]; + int read = read(single, 0, 1); + return read == -1 ? -1 : single[0] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return 0; + } + if (eof) { + return -1; + } + while (current == null || !current.hasRemaining()) { + current = chunks.take(); + if (current == END_OF_STREAM) { + eof = true; + return -1; + } + } + int toRead = Math.min(len, current.remaining()); + current.get(b, off, toRead); + return toRead; + } + } + + public ConnectionAgentH2cTransport(String host, int port) throws Exception { + this.selector = Selector.open(); + this.channel = SocketChannel.open(); + channel.configureBlocking(false); + channel.setOption(java.net.StandardSocketOptions.TCP_NODELAY, true); + channel.connect(new InetSocketAddress(host, port)); + while (!channel.finishConnect()) { + Thread.sleep(1); + } + this.selectionKey = channel.register(selector, SelectionKey.OP_READ); + readScratch.flip(); + + var started = new CompletableFuture(); + this.connectionThread = Thread.startVirtualThread(() -> run(started)); + started.get(10, TimeUnit.SECONDS); + } + + public HttpResponse send(HttpRequest request) throws IOException { + CompletableFuture future = new CompletableFuture<>(); + byte[] body = extractBody(request.body()); + tasks.offer(() -> startExchange(request, body, future)); + selector.wakeup(); + try { + return future.get(30, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IOException("Request failed", e); + } + } + + private static byte[] extractBody(DataStream body) throws IOException { + if (body == null || body.contentLength() == 0) { + return new byte[0]; + } + if (body.isReplayable() && body.hasKnownLength() && body.contentLength() <= Integer.MAX_VALUE) { + ByteBuffer buffer = body.asByteBuffer(); + if (!buffer.hasRemaining()) { + return new byte[0]; + } + if (buffer.hasArray()) { + int offset = buffer.arrayOffset() + buffer.position(); + int length = buffer.remaining(); + if (offset == 0 && length == buffer.array().length) { + return buffer.array(); + } + byte[] copy = new byte[length]; + System.arraycopy(buffer.array(), offset, copy, 0, length); + return copy; + } + byte[] copy = new byte[buffer.remaining()]; + buffer.get(copy); + return copy; + } + try (InputStream is = body.asInputStream()) { + return is.readAllBytes(); + } + } + + @Override + public void close() { + tasks.offer(() -> { + try { + selectionKey.cancel(); + channel.close(); + selector.close(); + } catch (IOException ignored) {} + }); + selector.wakeup(); + try { + connectionThread.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void run(CompletableFuture started) { + try { + writeRaw( + ConnectionAgentH2Constants.CONNECTION_PREFACE, + 0, + ConnectionAgentH2Constants.CONNECTION_PREFACE.length); + buildSettings(); + buildWindowUpdate( + 0, + TARGET_CONNECTION_WINDOW - ConnectionAgentH2Constants.DEFAULT_INITIAL_WINDOW_SIZE); + flushWriteScratch(); + started.complete(null); + + while (selector.isOpen()) { + drainTasks(); + flushWriteScratch(); + + int interestOps = SelectionKey.OP_READ | (writeScratch.position() > 0 ? SelectionKey.OP_WRITE : 0); + selectionKey.interestOps(interestOps); + selector.select(100); + + var keys = selector.selectedKeys(); + boolean anyRead = false; + for (var key : keys) { + if (key.isReadable()) { + int n = channel.read(readScratch.compact()); + readScratch.flip(); + if (n < 0 && !readScratch.hasRemaining()) { + throw new IOException("EOF"); + } + anyRead = n != 0; + } + if (key.isValid() && key.isWritable()) { + flushWriteScratch(); + } + } + keys.clear(); + if (anyRead || readScratch.hasRemaining()) { + pumpInbound(); + } + } + } catch (Throwable t) { + if (!started.isDone()) { + started.completeExceptionally(t); + } + for (StreamState stream : streams.values()) { + stream.body.fail(t); + stream.responseFuture.completeExceptionally(t); + } + streams.clear(); + } + } + + private void drainTasks() { + Runnable task; + while ((task = tasks.poll()) != null) { + task.run(); + } + } + + private void ensureWriteCapacity(int needed) throws IOException { + if (needed > writeScratch.capacity()) { + throw new IOException("Frame too large: " + needed); + } + while (writeScratch.remaining() < needed) { + flushWriteScratch(); + if (writeScratch.remaining() < needed) { + selectionKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + selector.select(100); + selector.selectedKeys().clear(); + } + } + } + + private void writeRaw(byte[] src, int off, int len) throws IOException { + while (len > 0) { + if (writeScratch.remaining() == 0) { + flushWriteScratch(); + } + int chunk = Math.min(writeScratch.remaining(), len); + writeScratch.put(src, off, chunk); + off += chunk; + len -= chunk; + } + } + + private void writeFrameHeader(int payloadLen, int type, int flags, int streamId) { + writeScratch.put((byte) ((payloadLen >> 16) & 0xFF)); + writeScratch.put((byte) ((payloadLen >> 8) & 0xFF)); + writeScratch.put((byte) (payloadLen & 0xFF)); + writeScratch.put((byte) type); + writeScratch.put((byte) flags); + writeScratch.put((byte) ((streamId >> 24) & 0x7F)); + writeScratch.put((byte) ((streamId >> 16) & 0xFF)); + writeScratch.put((byte) ((streamId >> 8) & 0xFF)); + writeScratch.put((byte) (streamId & 0xFF)); + } + + private void buildSettings() throws IOException { + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE + 6); + writeFrameHeader(6, ConnectionAgentH2Constants.FRAME_TYPE_SETTINGS, 0, 0); + writeScratch.putShort((short) 0x4); + writeScratch.putInt(16 * 1024 * 1024); + } + + private void buildSettingsAck() throws IOException { + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE); + writeFrameHeader( + 0, + ConnectionAgentH2Constants.FRAME_TYPE_SETTINGS, + ConnectionAgentH2Constants.FLAG_ACK, + 0); + } + + private void buildWindowUpdate(int streamId, int increment) throws IOException { + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE + 4); + writeFrameHeader(4, ConnectionAgentH2Constants.FRAME_TYPE_WINDOW_UPDATE, 0, streamId); + writeScratch.putInt(increment); + } + + private void buildPingAck(byte[] data) throws IOException { + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE + 8); + writeFrameHeader(8, ConnectionAgentH2Constants.FRAME_TYPE_PING, ConnectionAgentH2Constants.FLAG_ACK, 0); + writeScratch.put(data); + } + + private void flushWriteScratch() throws IOException { + if (writeScratch.position() == 0) { + return; + } + writeScratch.flip(); + try { + while (writeScratch.hasRemaining()) { + int n = channel.write(writeScratch); + if (n == 0) { + break; + } + } + } finally { + writeScratch.compact(); + } + } + + private void startExchange(HttpRequest request, byte[] body, CompletableFuture future) { + try { + int streamId = nextStreamId; + nextStreamId += 2; + var stream = new StreamState(streamId, remoteInitialWindow, future); + if (body.length > 0) { + stream.pendingRequestBody = ByteBuffer.wrap(body); + } + streams.put(streamId, stream); + + var headerBlock = encodeHeaders(request); + boolean endStream = body.length == 0; + stream.state.onHeadersEncoded(endStream); + int flags = ConnectionAgentH2Constants.FLAG_END_HEADERS + | (endStream ? ConnectionAgentH2Constants.FLAG_END_STREAM : 0); + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE + headerBlock.length); + writeFrameHeader(headerBlock.length, ConnectionAgentH2Constants.FRAME_TYPE_HEADERS, flags, streamId); + writeScratch.put(headerBlock); + + pumpStreamData(stream); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + + private byte[] encodeHeaders(HttpRequest request) throws IOException { + var out = new ByteArrayOutputStream(512); + var uri = request.uri(); + String path = uri.getPath(); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + path = path + "?" + uri.getQuery(); + } + encoder.encodeHeader(out, ConnectionAgentH2Constants.PSEUDO_METHOD, request.method(), false); + encoder.encodeHeader(out, ConnectionAgentH2Constants.PSEUDO_PATH, path, false); + encoder.encodeHeader(out, ConnectionAgentH2Constants.PSEUDO_SCHEME, uri.getScheme(), false); + String authority = uri.getHost() + (uri.getPort() > 0 ? ":" + uri.getPort() : ""); + encoder.encodeHeader(out, ConnectionAgentH2Constants.PSEUDO_AUTHORITY, authority, false); + for (Map.Entry> entry : request.headers().map().entrySet()) { + for (String value : entry.getValue()) { + encoder.encodeHeader(out, entry.getKey(), value, false); + } + } + return out.toByteArray(); + } + + private void pumpStreamData(StreamState stream) throws IOException { + if (stream.pendingRequestBody == null || stream.state.isEndStreamSent()) { + return; + } + while (stream.pendingRequestBody.hasRemaining()) { + int canSend = Math.min(Math.min(stream.sendWindow, sendWindow), remoteMaxFrame); + if (canSend <= 0) { + if (!unsentBodyStreams.contains(stream)) { + unsentBodyStreams.add(stream); + } + return; + } + int chunk = Math.min(canSend, stream.pendingRequestBody.remaining()); + boolean end = chunk == stream.pendingRequestBody.remaining(); + ensureWriteCapacity(ConnectionAgentH2Constants.FRAME_HEADER_SIZE + chunk); + writeFrameHeader( + chunk, + ConnectionAgentH2Constants.FRAME_TYPE_DATA, + end ? ConnectionAgentH2Constants.FLAG_END_STREAM : 0, + stream.streamId); + int oldLimit = stream.pendingRequestBody.limit(); + stream.pendingRequestBody.limit(stream.pendingRequestBody.position() + chunk); + writeScratch.put(stream.pendingRequestBody); + stream.pendingRequestBody.limit(oldLimit); + stream.sendWindow -= chunk; + sendWindow -= chunk; + if (end) { + stream.state.markEndStreamSent(); + } + } + } + + private void pumpInbound() throws IOException { + while (readScratch.hasRemaining()) { + int before = readScratch.remaining(); + parseFrames(); + if (readScratch.remaining() == before) { + break; + } + } + } + + private void parseFrames() throws IOException { + while (readScratch.hasRemaining()) { + if (!headerParsed) { + int want = ConnectionAgentH2Constants.FRAME_HEADER_SIZE - frameHdrBytes; + int take = Math.min(want, readScratch.remaining()); + readScratch.get(frameHdrBuf, frameHdrBytes, take); + frameHdrBytes += take; + if (frameHdrBytes < ConnectionAgentH2Constants.FRAME_HEADER_SIZE) { + return; + } + curPayloadLen = ((frameHdrBuf[0] & 0xFF) << 16) + | ((frameHdrBuf[1] & 0xFF) << 8) + | (frameHdrBuf[2] & 0xFF); + curType = frameHdrBuf[3] & 0xFF; + curFlags = frameHdrBuf[4] & 0xFF; + curStreamId = ((frameHdrBuf[5] & 0x7F) << 24) + | ((frameHdrBuf[6] & 0xFF) << 16) + | ((frameHdrBuf[7] & 0xFF) << 8) + | (frameHdrBuf[8] & 0xFF); + ConnectionAgentH2FrameOps.validateStreamId(curType, curStreamId); + ConnectionAgentH2FrameOps.validateFrameSize(curType, curFlags, curPayloadLen); + frameHdrBytes = 0; + headerParsed = true; + curPayloadRead = 0; + } + + if (curType == ConnectionAgentH2Constants.FRAME_TYPE_DATA) { + StreamState stream = streams.get(curStreamId); + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + if (take > 0) { + if (stream != null) { + byte[] tmp = copyBytes(take); + readScratch.get(tmp, 0, take); + stream.body.enqueue(tmp, take); + } else { + readScratch.position(readScratch.position() + take); + } + curPayloadRead += take; + } + if (curPayloadRead == curPayloadLen) { + onDataFrameEnd(stream); + resetFrameState(); + } else { + return; + } + } else { + if (curPayloadLen > 0) { + if (curStaged == null || curStaged.length < curPayloadLen) { + curStaged = new byte[Math.max(curPayloadLen, 256)]; + } + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + readScratch.get(curStaged, curPayloadRead, take); + curPayloadRead += take; + if (curPayloadRead < curPayloadLen) { + return; + } + } + dispatchControlFrame(); + resetFrameState(); + } + } + } + + private byte[] copyBytes(int size) { + if (copyScratch.length < size) { + copyScratch = new byte[Math.max(size, copyScratch.length * 2)]; + } + return new byte[size]; + } + + private void resetFrameState() { + headerParsed = false; + curPayloadRead = 0; + } + + private void onDataFrameEnd(StreamState stream) throws IOException { + recvWindow -= curPayloadLen; + if (recvWindow < 8 * 1024 * 1024) { + int increment = 16 * 1024 * 1024 - recvWindow; + recvWindow += increment; + buildWindowUpdate(0, increment); + } + if (stream != null && (curFlags & ConnectionAgentH2Constants.FLAG_END_STREAM) != 0) { + stream.state.markEndStreamReceived(); + completeStream(stream); + } + } + + private void dispatchControlFrame() throws IOException { + switch (curType) { + case ConnectionAgentH2Constants.FRAME_TYPE_SETTINGS -> handleSettings(); + case ConnectionAgentH2Constants.FRAME_TYPE_HEADERS -> handleHeaders(); + case ConnectionAgentH2Constants.FRAME_TYPE_WINDOW_UPDATE -> handleWindowUpdate(); + case ConnectionAgentH2Constants.FRAME_TYPE_RST_STREAM -> handleRst(); + case ConnectionAgentH2Constants.FRAME_TYPE_GOAWAY -> { + } + case ConnectionAgentH2Constants.FRAME_TYPE_PING -> { + if ((curFlags & ConnectionAgentH2Constants.FLAG_ACK) == 0 && curPayloadLen == 8) { + byte[] data = new byte[8]; + System.arraycopy(curStaged, 0, data, 0, 8); + buildPingAck(data); + } + } + default -> { + } + } + } + + private void handleSettings() throws IOException { + if ((curFlags & ConnectionAgentH2Constants.FLAG_ACK) != 0) { + return; + } + int i = 0; + while (i + 6 <= curPayloadLen) { + int id = ((curStaged[i] & 0xFF) << 8) | (curStaged[i + 1] & 0xFF); + int value = ((curStaged[i + 2] & 0xFF) << 24) + | ((curStaged[i + 3] & 0xFF) << 16) + | ((curStaged[i + 4] & 0xFF) << 8) + | (curStaged[i + 5] & 0xFF); + if (id == 0x4) { + int delta = value - remoteInitialWindow; + remoteInitialWindow = value; + for (StreamState stream : streams.values()) { + stream.sendWindow += delta; + } + } else if (id == 0x5) { + remoteMaxFrame = value; + } + i += 6; + } + buildSettingsAck(); + } + + private void handleHeaders() throws IOException { + StreamState stream = streams.get(curStreamId); + if (stream == null) { + return; + } + if ((curFlags & ConnectionAgentH2Constants.FLAG_END_HEADERS) == 0) { + throw new IOException("CONTINUATION unsupported in prototype"); + } + byte[] headerBlock = decodeScratch(curPayloadLen); + List fields = decoder.decode(headerBlock); + for (int i = 0; i < fields.size() - 1; i += 2) { + if (ConnectionAgentH2Constants.PSEUDO_STATUS.equals(fields.get(i))) { + stream.state.setResponseHeadersReceived(Integer.parseInt(fields.get(i + 1))); + break; + } + } + if (!stream.responseFuture.isDone() && stream.state.isResponseHeadersReceived()) { + startResponse(stream); + } + if ((curFlags & ConnectionAgentH2Constants.FLAG_END_STREAM) != 0) { + stream.state.markEndStreamReceived(); + completeStream(stream); + } + } + + private byte[] decodeScratch(int length) { + byte[] copy = new byte[length]; + System.arraycopy(curStaged, 0, copy, 0, length); + return copy; + } + + private void startResponse(StreamState stream) { + var response = HttpResponse.create() + .setHttpVersion(HttpVersion.HTTP_2) + .setStatusCode(stream.state.getStatusCode()) + .setHeaders(HttpHeaders.ofModifiable()) + .setBody(stream.body); + stream.responseFuture.complete(response); + } + + private void handleWindowUpdate() throws IOException { + if (curPayloadLen < 4) { + return; + } + int increment = (((curStaged[0] & 0x7F) << 24) + | ((curStaged[1] & 0xFF) << 16) + | ((curStaged[2] & 0xFF) << 8) + | (curStaged[3] & 0xFF)); + if (curStreamId == 0) { + sendWindow += increment; + int size = unsentBodyStreams.size(); + for (int i = 0; i < size; i++) { + StreamState stream = unsentBodyStreams.poll(); + if (stream != null && !stream.state.isEndStreamSent()) { + pumpStreamData(stream); + } + } + } else { + StreamState stream = streams.get(curStreamId); + if (stream != null) { + stream.sendWindow += increment; + if (!stream.state.isEndStreamSent()) { + pumpStreamData(stream); + } + } + } + } + + private void handleRst() { + StreamState stream = streams.remove(curStreamId); + if (stream != null) { + var error = new IOException("Stream reset by server"); + stream.body.fail(error); + stream.responseFuture.completeExceptionally(error); + } + } + + private void completeStream(StreamState stream) { + streams.remove(stream.streamId); + if (!stream.responseFuture.isDone()) { + startResponse(stream); + } + stream.body.complete(); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2Transport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2Transport.java new file mode 100644 index 0000000000..fa759e44c0 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2Transport.java @@ -0,0 +1,636 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Prototype event-loop H2 client using non-blocking TLS + single-thread-per-connection. + * See {@code EventLoopH2Transport} for the history; this version addresses allocation hotspots. + * + *

Key changes from the naive version: + *

    + *
  • Reuses a single large direct {@code writeScratch} buffer to build outbound frames + * instead of allocating per frame.
  • + *
  • Parses inbound frames directly out of the {@code readScratch} buffer without + * per-frame {@code ByteBuffer.allocate(payloadLen)}.
  • + *
  • DATA frame bodies are copied directly from the inbound buffer into the response + * {@code ByteArrayOutputStream} — one copy, not two.
  • + *
  • HEADERS encoding reuses a single {@code ByteArrayOutputStream} scratch.
  • + *
  • HPACK decoding avoids the intermediate {@code byte[]} copy by using a reusable + * staging buffer.
  • + *
+ * + *

Still prototype. Missing: connection pool, CONTINUATION, renegotiation, graceful close. + */ +public final class EventLoopH2Transport implements AutoCloseable { + + private static final byte[] PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(); + private static final int FRAME_HEADER_SIZE = 9; + private static final int TYPE_DATA = 0x0; + private static final int TYPE_HEADERS = 0x1; + private static final int TYPE_RST_STREAM = 0x3; + private static final int TYPE_SETTINGS = 0x4; + private static final int TYPE_PING = 0x6; + private static final int TYPE_GOAWAY = 0x7; + private static final int TYPE_WINDOW_UPDATE = 0x8; + private static final int FLAG_ACK = 0x1; + private static final int FLAG_END_STREAM = 0x1; + private static final int FLAG_END_HEADERS = 0x4; + private static final int DEFAULT_INITIAL_WINDOW = 65535; + private static final int DEFAULT_MAX_FRAME = 16384; + + // Size of outbound scratch buffer. Frames are built here then wrapped+written. + private static final int WRITE_SCRATCH_SIZE = 256 * 1024; + + private final Thread eventThread; + private final Selector selector; + private final NonBlockingSSLTransport tls; + private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>(); + + // Fields below: event-thread-only unless noted. + private final HpackEncoder encoder = new HpackEncoder(); + private final HpackDecoder decoder = new HpackDecoder(); + private final ByteBuffer readScratch = ByteBuffer.allocateDirect(1 << 17); // 128KB + private final ByteBuffer writeScratch = ByteBuffer.allocateDirect(WRITE_SCRATCH_SIZE); + private final ByteArrayOutputStream headerBuilder = new ByteArrayOutputStream(512); + private byte[] hpackDecodeScratch = new byte[1024]; + private final Map streams = new HashMap<>(); + private final ArrayDeque unsentBodyExchanges = new ArrayDeque<>(); + private int nextStreamId = 1; + private int sendWindow = DEFAULT_INITIAL_WINDOW; + private int recvWindow = 16 * 1024 * 1024; + private int remoteInitialWindow = DEFAULT_INITIAL_WINDOW; + private int remoteMaxFrame = DEFAULT_MAX_FRAME; + + // Inbound parse state - frame header buffered across reads + private int frameHdrBytes; + private final byte[] frameHdrBuf = new byte[FRAME_HEADER_SIZE]; + private int curPayloadLen; + private int curType; + private int curFlags; + private int curStreamId; + private int curPayloadRead; // bytes already copied into curStaged + private byte[] curStaged; // staging buffer for header/push payloads that need full assembly + private boolean headerParsed; + + private static final class Exchange { + final int streamId; + final CompletableFuture future; + int sendWindow; + int status; + final ByteArrayOutputStream body = new ByteArrayOutputStream(); + ByteBuffer pendingRequestBody; + boolean requestEndSent; + + Exchange(int streamId, int sendWindow, CompletableFuture future) { + this.streamId = streamId; + this.sendWindow = sendWindow; + this.future = future; + } + } + + public EventLoopH2Transport(String host, int port) throws Exception { + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(null, new TrustManager[] {new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + public void checkClientTrusted(X509Certificate[] c, String a) {} + + public void checkServerTrusted(X509Certificate[] c, String a) {} + }}, new SecureRandom()); + + this.selector = Selector.open(); + this.tls = NonBlockingSSLTransport.connect(host, port, sslCtx, selector); + readScratch.flip(); // start empty in read mode + + var started = new CompletableFuture(); + this.eventThread = new Thread(() -> run(started), "h2-eventloop-" + host); + eventThread.setDaemon(true); + eventThread.start(); + started.get(10, TimeUnit.SECONDS); + } + + public HttpResponse send(HttpRequest request) throws IOException { + CompletableFuture f = new CompletableFuture<>(); + byte[] body; + if (request.body() != null && request.body().contentLength() != 0) { + try (InputStream is = request.body().asInputStream()) { + body = is.readAllBytes(); + } + } else { + body = new byte[0]; + } + tasks.offer(() -> startExchange(request, body, f)); + selector.wakeup(); + try { + return f.get(30, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IOException("Request failed", e); + } + } + + @Override + public void close() { + tasks.offer(() -> { + try { + tls.close(); + } catch (IOException ignored) {} + }); + selector.wakeup(); + try { + eventThread.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + // ---- Event loop ---- + + private void run(CompletableFuture started) { + try { + while (!tls.handshakeComplete()) { + tls.handshakeStep(); + if (tls.handshakeComplete()) + break; + selector.select(1000); + } + // Send preface + initial SETTINGS + writeRaw(PREFACE, 0, PREFACE.length); + buildSettings(); + flushWriteScratch(); + started.complete(null); + + while (selector.isOpen()) { + Runnable t; + while ((t = tasks.poll()) != null) { + t.run(); + } + flushWriteScratch(); + int ops = SelectionKey.OP_READ; + if (writeScratch.position() > 0 || tls.netOutHasPending()) { + ops |= SelectionKey.OP_WRITE; + } + tls.setInterestOps(ops); + + selector.select(); + + var keys = selector.selectedKeys(); + boolean anyRead = false; + for (var key : keys) { + if (key.isReadable()) { + int n = tls.onReadable(); + if (n < 0 && tls.availablePlaintext() == 0) { + throw new IOException("EOF"); + } + anyRead = true; + } + if (key.isValid() && key.isWritable()) { + tls.flushNetOut(); + } + } + keys.clear(); + if (anyRead) { + pumpInbound(); + } + } + } catch (Throwable t) { + if (!started.isDone()) + started.completeExceptionally(t); + for (Exchange ex : streams.values()) + ex.future.completeExceptionally(t); + streams.clear(); + } + } + + // ---- Outbound: frames are assembled into writeScratch (direct) and wrapped on flush ---- + + /** Ensure writeScratch has at least `need` bytes of remaining capacity; blocks on socket if needed. */ + private void ensureWriteCapacity(int need) throws IOException { + if (need > writeScratch.capacity()) { + throw new IOException("Frame too large: " + need + " > " + writeScratch.capacity()); + } + while (writeScratch.remaining() < need) { + flushWriteScratch(); + if (writeScratch.remaining() < need) { + // Socket backpressured. Block on OP_WRITE to drain. + tls.setInterestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ); + selector.select(100); + selector.selectedKeys().clear(); + if (tls.netOutHasPending()) { + tls.flushNetOut(); + } + } + } + } + + private void writeRaw(byte[] src, int off, int len) throws IOException { + while (len > 0) { + if (writeScratch.remaining() == 0) { + flushWriteScratch(); + } + int chunk = Math.min(writeScratch.remaining(), len); + writeScratch.put(src, off, chunk); + off += chunk; + len -= chunk; + } + } + + private void writeFrameHeader(int payloadLen, int type, int flags, int streamId) { + writeScratch.put((byte) ((payloadLen >> 16) & 0xFF)); + writeScratch.put((byte) ((payloadLen >> 8) & 0xFF)); + writeScratch.put((byte) (payloadLen & 0xFF)); + writeScratch.put((byte) type); + writeScratch.put((byte) flags); + writeScratch.put((byte) ((streamId >> 24) & 0x7F)); + writeScratch.put((byte) ((streamId >> 16) & 0xFF)); + writeScratch.put((byte) ((streamId >> 8) & 0xFF)); + writeScratch.put((byte) (streamId & 0xFF)); + } + + private void buildSettings() throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 6); + writeFrameHeader(6, TYPE_SETTINGS, 0, 0); + writeScratch.putShort((short) 0x4); // SETTINGS_INITIAL_WINDOW_SIZE + writeScratch.putInt(16 * 1024 * 1024); + } + + private void buildSettingsAck() throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE); + writeFrameHeader(0, TYPE_SETTINGS, FLAG_ACK, 0); + } + + private void buildWindowUpdate(int streamId, int increment) throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 4); + writeFrameHeader(4, TYPE_WINDOW_UPDATE, 0, streamId); + writeScratch.putInt(increment); + } + + private void buildPingAck(byte[] data) throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 8); + writeFrameHeader(8, TYPE_PING, FLAG_ACK, 0); + writeScratch.put(data); + } + + /** Flushes writeScratch through SSL wrap into the socket. */ + private void flushWriteScratch() throws IOException { + if (writeScratch.position() == 0 && !tls.netOutHasPending()) { + return; + } + if (!tls.flushNetOut()) { + return; // socket full, retry later + } + writeScratch.flip(); + try { + while (writeScratch.hasRemaining()) { + tls.wrap(writeScratch); + if (!tls.flushNetOut()) { + break; + } + } + } finally { + writeScratch.compact(); + } + } + + // ---- Request start ---- + + private void startExchange(HttpRequest request, byte[] body, CompletableFuture future) { + try { + int id = nextStreamId; + nextStreamId += 2; + var ex = new Exchange(id, remoteInitialWindow, future); + if (body.length > 0) { + ex.pendingRequestBody = ByteBuffer.wrap(body); + } else { + ex.requestEndSent = true; + } + streams.put(id, ex); + + // Encode HEADERS + headerBuilder.reset(); + var uri = request.uri(); + String path = uri.getPath(); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + path = path + "?" + uri.getQuery(); + } + encoder.encodeHeader(headerBuilder, ":method", request.method(), false); + encoder.encodeHeader(headerBuilder, ":path", path, false); + encoder.encodeHeader(headerBuilder, ":scheme", uri.getScheme(), false); + String authority = uri.getHost() + (uri.getPort() > 0 ? ":" + uri.getPort() : ""); + encoder.encodeHeader(headerBuilder, ":authority", authority, false); + for (Map.Entry> e : request.headers().map().entrySet()) { + for (String v : e.getValue()) { + encoder.encodeHeader(headerBuilder, e.getKey(), v, false); + } + } + byte[] hpackBuf = headerBuilder.toByteArray(); + + int flags = FLAG_END_HEADERS | (body.length == 0 ? FLAG_END_STREAM : 0); + ensureWriteCapacity(FRAME_HEADER_SIZE + hpackBuf.length); + writeFrameHeader(hpackBuf.length, TYPE_HEADERS, flags, id); + writeScratch.put(hpackBuf); + + pumpExchangeData(ex); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + + private void pumpExchangeData(Exchange ex) throws IOException { + if (ex.pendingRequestBody == null || ex.requestEndSent) { + return; + } + while (ex.pendingRequestBody.hasRemaining()) { + int canSend = Math.min(Math.min(ex.sendWindow, sendWindow), remoteMaxFrame); + if (canSend <= 0) { + if (!unsentBodyExchanges.contains(ex)) + unsentBodyExchanges.add(ex); + return; + } + int chunk = Math.min(canSend, ex.pendingRequestBody.remaining()); + boolean end = chunk == ex.pendingRequestBody.remaining(); + int flags = end ? FLAG_END_STREAM : 0; + + ensureWriteCapacity(FRAME_HEADER_SIZE + chunk); + writeFrameHeader(chunk, TYPE_DATA, flags, ex.streamId); + int oldLimit = ex.pendingRequestBody.limit(); + ex.pendingRequestBody.limit(ex.pendingRequestBody.position() + chunk); + writeScratch.put(ex.pendingRequestBody); + ex.pendingRequestBody.limit(oldLimit); + + ex.sendWindow -= chunk; + sendWindow -= chunk; + if (end) { + ex.requestEndSent = true; + } + } + } + + // ---- Inbound: parse frames directly from TLS plaintext, no per-frame allocation ---- + + private void pumpInbound() throws IOException { + while (tls.availablePlaintext() > 0 || readScratch.hasRemaining()) { + if (tls.availablePlaintext() > 0) { + readScratch.compact(); + tls.readPlaintext(readScratch); + readScratch.flip(); + } + int before = readScratch.remaining(); + parseFrames(); + int after = readScratch.remaining(); + if (after == before && tls.availablePlaintext() == 0) { + break; // no progress possible + } + } + } + + private void parseFrames() throws IOException { + while (readScratch.hasRemaining()) { + if (!headerParsed) { + // Read header bytes into frameHdrBuf + int want = FRAME_HEADER_SIZE - frameHdrBytes; + int take = Math.min(want, readScratch.remaining()); + readScratch.get(frameHdrBuf, frameHdrBytes, take); + frameHdrBytes += take; + if (frameHdrBytes < FRAME_HEADER_SIZE) + return; + + curPayloadLen = ((frameHdrBuf[0] & 0xFF) << 16) + | ((frameHdrBuf[1] & 0xFF) << 8) + | (frameHdrBuf[2] & 0xFF); + curType = frameHdrBuf[3] & 0xFF; + curFlags = frameHdrBuf[4] & 0xFF; + curStreamId = ((frameHdrBuf[5] & 0x7F) << 24) + | ((frameHdrBuf[6] & 0xFF) << 16) + | ((frameHdrBuf[7] & 0xFF) << 8) + | (frameHdrBuf[8] & 0xFF); + frameHdrBytes = 0; + headerParsed = true; + curPayloadRead = 0; + } + + // We have a header, now consume payload + if (curType == TYPE_DATA) { + // Stream DATA straight into the exchange body buffer — one copy + Exchange ex = streams.get(curStreamId); + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + if (take > 0) { + if (ex != null) { + // Copy from direct read buffer to exchange's ByteArrayOutputStream + byte[] tmp = borrowTmp(take); + readScratch.get(tmp, 0, take); + ex.body.write(tmp, 0, take); + } else { + // Drop bytes + readScratch.position(readScratch.position() + take); + } + curPayloadRead += take; + } + if (curPayloadRead == curPayloadLen) { + onDataFrameEnd(ex); + resetFrameState(); + } else { + return; // need more data + } + } else { + // Non-DATA: buffer the payload in curStaged (one alloc per frame, but these are rare) + if (curPayloadLen > 0) { + if (curStaged == null || curStaged.length < curPayloadLen) { + curStaged = new byte[Math.max(curPayloadLen, 256)]; + } + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + readScratch.get(curStaged, curPayloadRead, take); + curPayloadRead += take; + if (curPayloadRead < curPayloadLen) { + return; // need more + } + } + dispatchControlFrame(); + resetFrameState(); + } + } + } + + // Reusable scratch array to copy from direct buffer. Single-thread so no sync. + private byte[] copyScratch = new byte[8192]; + + private byte[] borrowTmp(int size) { + if (copyScratch.length < size) { + copyScratch = new byte[Math.max(size, copyScratch.length * 2)]; + } + return copyScratch; + } + + private void resetFrameState() { + headerParsed = false; + curPayloadRead = 0; + } + + private void onDataFrameEnd(Exchange ex) throws IOException { + // Connection-level receive flow control + recvWindow -= curPayloadLen; + if (recvWindow < 8 * 1024 * 1024) { + int inc = 16 * 1024 * 1024 - recvWindow; + recvWindow += inc; + buildWindowUpdate(0, inc); + } + if (ex != null && (curFlags & FLAG_END_STREAM) != 0) { + completeExchange(ex); + } + } + + private void dispatchControlFrame() throws IOException { + switch (curType) { + case TYPE_SETTINGS -> handleSettings(); + case TYPE_HEADERS -> handleHeaders(); + case TYPE_WINDOW_UPDATE -> handleWindowUpdate(); + case TYPE_RST_STREAM -> handleRst(); + case TYPE_GOAWAY -> { + /* ignored */ } + case TYPE_PING -> { + if ((curFlags & FLAG_ACK) == 0 && curPayloadLen == 8) { + byte[] data = new byte[8]; + System.arraycopy(curStaged, 0, data, 0, 8); + buildPingAck(data); + } + } + default -> { + } + } + } + + private void handleSettings() throws IOException { + if ((curFlags & FLAG_ACK) != 0) { + return; + } + int i = 0; + while (i + 6 <= curPayloadLen) { + int id = ((curStaged[i] & 0xFF) << 8) | (curStaged[i + 1] & 0xFF); + int value = ((curStaged[i + 2] & 0xFF) << 24) + | ((curStaged[i + 3] & 0xFF) << 16) + | ((curStaged[i + 4] & 0xFF) << 8) + | (curStaged[i + 5] & 0xFF); + if (id == 0x4) { + int delta = value - remoteInitialWindow; + remoteInitialWindow = value; + for (Exchange ex : streams.values()) + ex.sendWindow += delta; + } else if (id == 0x5) { + remoteMaxFrame = value; + } + i += 6; + } + buildSettingsAck(); + } + + private void handleHeaders() throws IOException { + Exchange ex = streams.get(curStreamId); + if (ex == null) + return; + if ((curFlags & FLAG_END_HEADERS) == 0) { + throw new IOException("CONTINUATION unsupported in prototype"); + } + // HpackDecoder.decode takes a byte[] — resize our reusable buffer if needed + byte[] hpackInput; + if (curPayloadLen == curStaged.length) { + hpackInput = curStaged; + } else { + if (hpackDecodeScratch.length < curPayloadLen) { + hpackDecodeScratch = new byte[curPayloadLen]; + } + System.arraycopy(curStaged, 0, hpackDecodeScratch, 0, curPayloadLen); + hpackInput = hpackDecodeScratch; + // Zero out the tail so HpackDecoder sees an array of the exact right logical length + // Actually HpackDecoder uses the full length of the byte[] passed, so we must size it exactly. + if (hpackInput.length != curPayloadLen) { + hpackInput = new byte[curPayloadLen]; + System.arraycopy(curStaged, 0, hpackInput, 0, curPayloadLen); + } + } + List fields = decoder.decode(hpackInput); + for (int i = 0; i < fields.size() - 1; i += 2) { + if (":status".equals(fields.get(i))) { + ex.status = Integer.parseInt(fields.get(i + 1)); + break; + } + } + if ((curFlags & FLAG_END_STREAM) != 0) { + completeExchange(ex); + } + } + + private void handleWindowUpdate() throws IOException { + if (curPayloadLen < 4) + return; + int increment = (((curStaged[0] & 0x7F) << 24) + | ((curStaged[1] & 0xFF) << 16) + | ((curStaged[2] & 0xFF) << 8) + | (curStaged[3] & 0xFF)); + if (curStreamId == 0) { + sendWindow += increment; + // Drain any exchanges that were blocked on flow control + int size = unsentBodyExchanges.size(); + for (int k = 0; k < size; k++) { + Exchange ex = unsentBodyExchanges.poll(); + if (ex != null && !ex.requestEndSent) { + pumpExchangeData(ex); + } + } + } else { + Exchange ex = streams.get(curStreamId); + if (ex != null) { + ex.sendWindow += increment; + if (!ex.requestEndSent) + pumpExchangeData(ex); + } + } + } + + private void handleRst() { + Exchange ex = streams.remove(curStreamId); + if (ex != null) { + ex.future.completeExceptionally(new IOException("Stream reset by server")); + } + } + + private void completeExchange(Exchange ex) { + streams.remove(ex.streamId); + byte[] body = ex.body.toByteArray(); + var response = HttpResponse.create() + .setHttpVersion(HttpVersion.HTTP_2) + .setStatusCode(ex.status) + .setHeaders(HttpHeaders.ofModifiable()) + .setBody(DataStream.ofBytes(body)); + ex.future.complete(response); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2cTransport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2cTransport.java new file mode 100644 index 0000000000..0abaf65603 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/EventLoopH2cTransport.java @@ -0,0 +1,582 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Benchmark-only single-loop H2C transport. + * + *

One event-loop thread owns both reads and writes for a connection so there is no reader/writer + * thread split. Request bodies and response bodies are fully materialized, which is acceptable for + * benchmarking but not a production design. + */ +public final class EventLoopH2cTransport implements AutoCloseable { + + private static final byte[] PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(); + private static final int FRAME_HEADER_SIZE = 9; + private static final int TYPE_DATA = 0x0; + private static final int TYPE_HEADERS = 0x1; + private static final int TYPE_RST_STREAM = 0x3; + private static final int TYPE_SETTINGS = 0x4; + private static final int TYPE_PING = 0x6; + private static final int TYPE_GOAWAY = 0x7; + private static final int TYPE_WINDOW_UPDATE = 0x8; + private static final int FLAG_ACK = 0x1; + private static final int FLAG_END_STREAM = 0x1; + private static final int FLAG_END_HEADERS = 0x4; + private static final int DEFAULT_INITIAL_WINDOW = 65535; + private static final int DEFAULT_MAX_FRAME = 16384; + private static final int TARGET_CONNECTION_WINDOW = 16 * 1024 * 1024; + private static final int WRITE_SCRATCH_SIZE = 256 * 1024; + + private final Thread eventThread; + private final Selector selector; + private final SocketChannel channel; + private final SelectionKey selectionKey; + private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>(); + + // Event-thread only fields. + private final HpackEncoder encoder = new HpackEncoder(); + private final HpackDecoder decoder = new HpackDecoder(); + private final ByteBuffer readScratch = ByteBuffer.allocateDirect(1 << 17); + private final ByteBuffer writeScratch = ByteBuffer.allocateDirect(WRITE_SCRATCH_SIZE); + private final ByteArrayOutputStream headerBuilder = new ByteArrayOutputStream(512); + private byte[] hpackDecodeScratch = new byte[1024]; + private final Map streams = new HashMap<>(); + private final ArrayDeque unsentBodyExchanges = new ArrayDeque<>(); + private int nextStreamId = 1; + private int sendWindow = DEFAULT_INITIAL_WINDOW; + private int recvWindow = TARGET_CONNECTION_WINDOW; + private int remoteInitialWindow = DEFAULT_INITIAL_WINDOW; + private int remoteMaxFrame = DEFAULT_MAX_FRAME; + + private int frameHdrBytes; + private final byte[] frameHdrBuf = new byte[FRAME_HEADER_SIZE]; + private int curPayloadLen; + private int curType; + private int curFlags; + private int curStreamId; + private int curPayloadRead; + private byte[] curStaged; + private boolean headerParsed; + + private byte[] copyScratch = new byte[8192]; + + private static final class Exchange { + final int streamId; + final CompletableFuture future; + int sendWindow; + int status; + final ByteArrayOutputStream body = new ByteArrayOutputStream(); + ByteBuffer pendingRequestBody; + boolean requestEndSent; + + Exchange(int streamId, int sendWindow, CompletableFuture future) { + this.streamId = streamId; + this.sendWindow = sendWindow; + this.future = future; + } + } + + public EventLoopH2cTransport(String host, int port) throws Exception { + this.selector = Selector.open(); + this.channel = SocketChannel.open(); + channel.configureBlocking(false); + channel.setOption(java.net.StandardSocketOptions.TCP_NODELAY, true); + channel.connect(new InetSocketAddress(host, port)); + while (!channel.finishConnect()) { + Thread.sleep(1); + } + this.selectionKey = channel.register(selector, SelectionKey.OP_READ); + readScratch.flip(); + + var started = new CompletableFuture(); + this.eventThread = new Thread(() -> run(started), "h2c-eventloop-" + host); + eventThread.setDaemon(true); + eventThread.start(); + started.get(10, TimeUnit.SECONDS); + } + + public HttpResponse send(HttpRequest request) throws IOException { + CompletableFuture future = new CompletableFuture<>(); + byte[] body; + if (request.body() != null && request.body().contentLength() != 0) { + try (InputStream is = request.body().asInputStream()) { + body = is.readAllBytes(); + } + } else { + body = new byte[0]; + } + tasks.offer(() -> startExchange(request, body, future)); + selector.wakeup(); + try { + return future.get(30, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IOException("Request failed", e); + } + } + + @Override + public void close() { + tasks.offer(() -> { + try { + selectionKey.cancel(); + channel.close(); + selector.close(); + } catch (IOException ignored) {} + }); + selector.wakeup(); + try { + eventThread.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void run(CompletableFuture started) { + try { + writeRaw(PREFACE, 0, PREFACE.length); + buildSettings(); + buildWindowUpdate(0, TARGET_CONNECTION_WINDOW - DEFAULT_INITIAL_WINDOW); + flushWriteScratch(); + started.complete(null); + + while (selector.isOpen()) { + Runnable task; + while ((task = tasks.poll()) != null) { + task.run(); + } + + flushWriteScratch(); + int ops = SelectionKey.OP_READ | (writeScratch.position() > 0 ? SelectionKey.OP_WRITE : 0); + selectionKey.interestOps(ops); + + selector.select(100); + var keys = selector.selectedKeys(); + boolean anyRead = false; + for (var key : keys) { + if (key.isReadable()) { + int n = channel.read(readScratch.compact()); + readScratch.flip(); + if (n < 0 && !readScratch.hasRemaining()) { + throw new IOException("EOF"); + } + anyRead = n != 0; + } + if (key.isValid() && key.isWritable()) { + flushWriteScratch(); + } + } + keys.clear(); + if (anyRead || readScratch.hasRemaining()) { + pumpInbound(); + } + } + } catch (Throwable t) { + if (!started.isDone()) { + started.completeExceptionally(t); + } + for (Exchange ex : streams.values()) { + ex.future.completeExceptionally(t); + } + streams.clear(); + } + } + + private void ensureWriteCapacity(int need) throws IOException { + if (need > writeScratch.capacity()) { + throw new IOException("Frame too large: " + need + " > " + writeScratch.capacity()); + } + while (writeScratch.remaining() < need) { + flushWriteScratch(); + if (writeScratch.remaining() < need) { + selectionKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + selector.select(100); + selector.selectedKeys().clear(); + } + } + } + + private void writeRaw(byte[] src, int off, int len) throws IOException { + while (len > 0) { + if (writeScratch.remaining() == 0) { + flushWriteScratch(); + } + int chunk = Math.min(writeScratch.remaining(), len); + writeScratch.put(src, off, chunk); + off += chunk; + len -= chunk; + } + } + + private void writeFrameHeader(int payloadLen, int type, int flags, int streamId) { + writeScratch.put((byte) ((payloadLen >> 16) & 0xFF)); + writeScratch.put((byte) ((payloadLen >> 8) & 0xFF)); + writeScratch.put((byte) (payloadLen & 0xFF)); + writeScratch.put((byte) type); + writeScratch.put((byte) flags); + writeScratch.put((byte) ((streamId >> 24) & 0x7F)); + writeScratch.put((byte) ((streamId >> 16) & 0xFF)); + writeScratch.put((byte) ((streamId >> 8) & 0xFF)); + writeScratch.put((byte) (streamId & 0xFF)); + } + + private void buildSettings() throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 6); + writeFrameHeader(6, TYPE_SETTINGS, 0, 0); + writeScratch.putShort((short) 0x4); + writeScratch.putInt(16 * 1024 * 1024); + } + + private void buildSettingsAck() throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE); + writeFrameHeader(0, TYPE_SETTINGS, FLAG_ACK, 0); + } + + private void buildWindowUpdate(int streamId, int increment) throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 4); + writeFrameHeader(4, TYPE_WINDOW_UPDATE, 0, streamId); + writeScratch.putInt(increment); + } + + private void buildPingAck(byte[] data) throws IOException { + ensureWriteCapacity(FRAME_HEADER_SIZE + 8); + writeFrameHeader(8, TYPE_PING, FLAG_ACK, 0); + writeScratch.put(data); + } + + private void flushWriteScratch() throws IOException { + if (writeScratch.position() == 0) { + return; + } + writeScratch.flip(); + try { + while (writeScratch.hasRemaining()) { + int n = channel.write(writeScratch); + if (n == 0) { + break; + } + } + } finally { + writeScratch.compact(); + } + } + + private void startExchange(HttpRequest request, byte[] body, CompletableFuture future) { + try { + int streamId = nextStreamId; + nextStreamId += 2; + var ex = new Exchange(streamId, remoteInitialWindow, future); + if (body.length > 0) { + ex.pendingRequestBody = ByteBuffer.wrap(body); + } else { + ex.requestEndSent = true; + } + streams.put(streamId, ex); + + headerBuilder.reset(); + var uri = request.uri(); + String path = uri.getPath(); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + path = path + "?" + uri.getQuery(); + } + encoder.encodeHeader(headerBuilder, ":method", request.method(), false); + encoder.encodeHeader(headerBuilder, ":path", path, false); + encoder.encodeHeader(headerBuilder, ":scheme", uri.getScheme(), false); + String authority = uri.getHost() + (uri.getPort() > 0 ? ":" + uri.getPort() : ""); + encoder.encodeHeader(headerBuilder, ":authority", authority, false); + for (Map.Entry> e : request.headers().map().entrySet()) { + for (String value : e.getValue()) { + encoder.encodeHeader(headerBuilder, e.getKey(), value, false); + } + } + byte[] hpackBuf = headerBuilder.toByteArray(); + + int flags = FLAG_END_HEADERS | (body.length == 0 ? FLAG_END_STREAM : 0); + ensureWriteCapacity(FRAME_HEADER_SIZE + hpackBuf.length); + writeFrameHeader(hpackBuf.length, TYPE_HEADERS, flags, streamId); + writeScratch.put(hpackBuf); + + pumpExchangeData(ex); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + + private void pumpExchangeData(Exchange ex) throws IOException { + if (ex.pendingRequestBody == null || ex.requestEndSent) { + return; + } + while (ex.pendingRequestBody.hasRemaining()) { + int canSend = Math.min(Math.min(ex.sendWindow, sendWindow), remoteMaxFrame); + if (canSend <= 0) { + if (!unsentBodyExchanges.contains(ex)) { + unsentBodyExchanges.add(ex); + } + return; + } + + int chunk = Math.min(canSend, ex.pendingRequestBody.remaining()); + boolean end = chunk == ex.pendingRequestBody.remaining(); + int flags = end ? FLAG_END_STREAM : 0; + ensureWriteCapacity(FRAME_HEADER_SIZE + chunk); + writeFrameHeader(chunk, TYPE_DATA, flags, ex.streamId); + int oldLimit = ex.pendingRequestBody.limit(); + ex.pendingRequestBody.limit(ex.pendingRequestBody.position() + chunk); + writeScratch.put(ex.pendingRequestBody); + ex.pendingRequestBody.limit(oldLimit); + + ex.sendWindow -= chunk; + sendWindow -= chunk; + if (end) { + ex.requestEndSent = true; + } + } + } + + private void pumpInbound() throws IOException { + while (readScratch.hasRemaining()) { + int before = readScratch.remaining(); + parseFrames(); + if (readScratch.remaining() == before) { + break; + } + } + } + + private void parseFrames() throws IOException { + while (readScratch.hasRemaining()) { + if (!headerParsed) { + int want = FRAME_HEADER_SIZE - frameHdrBytes; + int take = Math.min(want, readScratch.remaining()); + readScratch.get(frameHdrBuf, frameHdrBytes, take); + frameHdrBytes += take; + if (frameHdrBytes < FRAME_HEADER_SIZE) { + return; + } + + curPayloadLen = ((frameHdrBuf[0] & 0xFF) << 16) + | ((frameHdrBuf[1] & 0xFF) << 8) + | (frameHdrBuf[2] & 0xFF); + curType = frameHdrBuf[3] & 0xFF; + curFlags = frameHdrBuf[4] & 0xFF; + curStreamId = ((frameHdrBuf[5] & 0x7F) << 24) + | ((frameHdrBuf[6] & 0xFF) << 16) + | ((frameHdrBuf[7] & 0xFF) << 8) + | (frameHdrBuf[8] & 0xFF); + frameHdrBytes = 0; + headerParsed = true; + curPayloadRead = 0; + } + + if (curType == TYPE_DATA) { + Exchange ex = streams.get(curStreamId); + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + if (take > 0) { + if (ex != null) { + byte[] tmp = borrowTmp(take); + readScratch.get(tmp, 0, take); + ex.body.write(tmp, 0, take); + } else { + readScratch.position(readScratch.position() + take); + } + curPayloadRead += take; + } + if (curPayloadRead == curPayloadLen) { + onDataFrameEnd(ex); + resetFrameState(); + } else { + return; + } + } else { + if (curPayloadLen > 0) { + if (curStaged == null || curStaged.length < curPayloadLen) { + curStaged = new byte[Math.max(curPayloadLen, 256)]; + } + int remaining = curPayloadLen - curPayloadRead; + int take = Math.min(remaining, readScratch.remaining()); + readScratch.get(curStaged, curPayloadRead, take); + curPayloadRead += take; + if (curPayloadRead < curPayloadLen) { + return; + } + } + dispatchControlFrame(); + resetFrameState(); + } + } + } + + private byte[] borrowTmp(int size) { + if (copyScratch.length < size) { + copyScratch = new byte[Math.max(size, copyScratch.length * 2)]; + } + return copyScratch; + } + + private void resetFrameState() { + headerParsed = false; + curPayloadRead = 0; + } + + private void onDataFrameEnd(Exchange ex) throws IOException { + recvWindow -= curPayloadLen; + if (recvWindow < 8 * 1024 * 1024) { + int increment = 16 * 1024 * 1024 - recvWindow; + recvWindow += increment; + buildWindowUpdate(0, increment); + } + if (ex != null && (curFlags & FLAG_END_STREAM) != 0) { + completeExchange(ex); + } + } + + private void dispatchControlFrame() throws IOException { + switch (curType) { + case TYPE_SETTINGS -> handleSettings(); + case TYPE_HEADERS -> handleHeaders(); + case TYPE_WINDOW_UPDATE -> handleWindowUpdate(); + case TYPE_RST_STREAM -> handleRst(); + case TYPE_GOAWAY -> { + } + case TYPE_PING -> { + if ((curFlags & FLAG_ACK) == 0 && curPayloadLen == 8) { + byte[] data = new byte[8]; + System.arraycopy(curStaged, 0, data, 0, 8); + buildPingAck(data); + } + } + default -> { + } + } + } + + private void handleSettings() throws IOException { + if ((curFlags & FLAG_ACK) != 0) { + return; + } + int i = 0; + while (i + 6 <= curPayloadLen) { + int id = ((curStaged[i] & 0xFF) << 8) | (curStaged[i + 1] & 0xFF); + int value = ((curStaged[i + 2] & 0xFF) << 24) + | ((curStaged[i + 3] & 0xFF) << 16) + | ((curStaged[i + 4] & 0xFF) << 8) + | (curStaged[i + 5] & 0xFF); + if (id == 0x4) { + int delta = value - remoteInitialWindow; + remoteInitialWindow = value; + for (Exchange ex : streams.values()) { + ex.sendWindow += delta; + } + } else if (id == 0x5) { + remoteMaxFrame = value; + } + i += 6; + } + buildSettingsAck(); + } + + private void handleHeaders() throws IOException { + Exchange ex = streams.get(curStreamId); + if (ex == null) { + return; + } + if ((curFlags & FLAG_END_HEADERS) == 0) { + throw new IOException("CONTINUATION unsupported in prototype"); + } + byte[] hpackInput; + if (curPayloadLen == curStaged.length) { + hpackInput = curStaged; + } else { + if (hpackDecodeScratch.length < curPayloadLen) { + hpackDecodeScratch = new byte[curPayloadLen]; + } + System.arraycopy(curStaged, 0, hpackDecodeScratch, 0, curPayloadLen); + hpackInput = hpackDecodeScratch; + if (hpackInput.length != curPayloadLen) { + hpackInput = new byte[curPayloadLen]; + System.arraycopy(curStaged, 0, hpackInput, 0, curPayloadLen); + } + } + List fields = decoder.decode(hpackInput); + for (int i = 0; i < fields.size() - 1; i += 2) { + if (":status".equals(fields.get(i))) { + ex.status = Integer.parseInt(fields.get(i + 1)); + break; + } + } + if ((curFlags & FLAG_END_STREAM) != 0) { + completeExchange(ex); + } + } + + private void handleWindowUpdate() throws IOException { + if (curPayloadLen < 4) { + return; + } + int increment = (((curStaged[0] & 0x7F) << 24) + | ((curStaged[1] & 0xFF) << 16) + | ((curStaged[2] & 0xFF) << 8) + | (curStaged[3] & 0xFF)); + if (curStreamId == 0) { + sendWindow += increment; + int size = unsentBodyExchanges.size(); + for (int k = 0; k < size; k++) { + Exchange ex = unsentBodyExchanges.poll(); + if (ex != null && !ex.requestEndSent) { + pumpExchangeData(ex); + } + } + } else { + Exchange ex = streams.get(curStreamId); + if (ex != null) { + ex.sendWindow += increment; + if (!ex.requestEndSent) { + pumpExchangeData(ex); + } + } + } + } + + private void handleRst() { + Exchange ex = streams.remove(curStreamId); + if (ex != null) { + ex.future.completeExceptionally(new IOException("Stream reset by server")); + } + } + + private void completeExchange(Exchange ex) { + streams.remove(ex.streamId); + byte[] body = ex.body.toByteArray(); + var response = HttpResponse.create() + .setHttpVersion(HttpVersion.HTTP_2) + .setStatusCode(ex.status) + .setHeaders(HttpHeaders.ofModifiable()) + .setBody(DataStream.ofBytes(body)); + ex.future.complete(response); + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/NonBlockingSSLTransport.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/NonBlockingSSLTransport.java new file mode 100644 index 0000000000..bc07e08f04 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/NonBlockingSSLTransport.java @@ -0,0 +1,320 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; + +/** + * Non-blocking TLS transport driven by an external selector loop. + * + *

Unlike {@code SSLEngineTransport} which blocks on socket I/O, this transport + * exposes non-blocking read/write methods and lets the caller drive the + * {@link Selector} loop. The event loop is responsible for: + *

    + *
  • Calling {@link #onReadable()} when the socket has bytes to read
  • + *
  • Calling {@link #onWritable()} when the socket can accept more writes
  • + *
  • Calling {@link #handshakeStep()} until handshake completes
  • + *
  • Calling {@link #wrap(ByteBuffer)} to encrypt application data
  • + *
  • Calling {@link #readPlaintext(ByteBuffer)} to consume decrypted data
  • + *
+ * + *

Prototype only. Skips: renegotiation, graceful close_notify, delegated tasks on + * a thread pool (runs them inline). + */ +final class NonBlockingSSLTransport { + + private final SocketChannel channel; + private final SSLEngine engine; + private final SelectionKey key; + + // Network ciphertext buffers (direct). + // netIn: write-mode (accumulating bytes from socket). netOut: write-mode (accumulating wrap output). + private ByteBuffer netIn; + private ByteBuffer netOut; + // Application plaintext buffer (read-mode, contains decrypted bytes not yet consumed). + private ByteBuffer appIn; + + private boolean handshakeComplete; + private boolean eof; + + NonBlockingSSLTransport(SocketChannel channel, SSLEngine engine, Selector selector) throws IOException { + this.channel = channel; + this.engine = engine; + channel.configureBlocking(false); + this.key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, this); + + int packetSize = engine.getSession().getPacketBufferSize(); + int appSize = engine.getSession().getApplicationBufferSize(); + this.netIn = ByteBuffer.allocateDirect(packetSize); // write mode + this.netOut = ByteBuffer.allocateDirect(packetSize); // write mode + this.appIn = ByteBuffer.allocate(appSize); + this.appIn.flip(); // read mode (empty) + } + + static NonBlockingSSLTransport connect(String host, int port, SSLContext sslCtx, Selector selector) + throws IOException { + SocketChannel ch = SocketChannel.open(); + ch.configureBlocking(false); + ch.setOption(java.net.StandardSocketOptions.TCP_NODELAY, true); + ch.connect(new InetSocketAddress(host, port)); + // Wait for connect to finish + while (!ch.finishConnect()) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted during connect", e); + } + } + SSLEngine engine = sslCtx.createSSLEngine(host, port); + engine.setUseClientMode(true); + var params = engine.getSSLParameters(); + params.setApplicationProtocols(new String[] {"h2"}); + engine.setSSLParameters(params); + engine.beginHandshake(); + return new NonBlockingSSLTransport(ch, engine, selector); + } + + SelectionKey selectionKey() { + return key; + } + + SocketChannel channel() { + return channel; + } + + boolean handshakeComplete() { + return handshakeComplete; + } + + boolean eof() { + return eof; + } + + String applicationProtocol() { + return engine.getApplicationProtocol(); + } + + /** + * Drive the handshake state machine as far as it will go with currently available data. + * Call repeatedly as OP_READ/OP_WRITE events fire until {@link #handshakeComplete()} returns true. + */ + void handshakeStep() throws IOException { + if (handshakeComplete) { + return; + } + HandshakeStatus hs = engine.getHandshakeStatus(); + while (!handshakeComplete) { + switch (hs) { + case NEED_WRAP -> { + SSLEngineResult r = wrapEmpty(); + if (r.getStatus() == Status.BUFFER_OVERFLOW) { + return; // wait for socket writable to drain netOut + } + // flush immediately + if (!flushNetOut()) { + return; // socket full, retry on OP_WRITE + } + hs = r.getHandshakeStatus(); + } + case NEED_UNWRAP, NEED_UNWRAP_AGAIN -> { + // Read more if nothing buffered + if (netIn.position() == 0) { + int n = channel.read(netIn); + if (n < 0) { + eof = true; + throw new SSLException("EOF during handshake"); + } + if (n == 0) { + return; // need more data + } + } + netIn.flip(); + ByteBuffer scratch = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); + SSLEngineResult r = engine.unwrap(netIn, scratch); + netIn.compact(); + if (r.getStatus() == Status.BUFFER_UNDERFLOW) { + return; // need more data + } + if (r.getStatus() == Status.CLOSED) { + eof = true; + throw new SSLException("Engine closed during handshake"); + } + hs = r.getHandshakeStatus(); + } + case NEED_TASK -> { + Runnable t; + while ((t = engine.getDelegatedTask()) != null) { + t.run(); + } + hs = engine.getHandshakeStatus(); + } + case FINISHED, NOT_HANDSHAKING -> { + handshakeComplete = true; + return; + } + } + } + } + + private SSLEngineResult wrapEmpty() throws IOException { + ByteBuffer empty = ByteBuffer.allocate(0); + return engine.wrap(empty, netOut); + } + + /** + * Flush any pending wrapped bytes to the socket. + * @return true if netOut is fully drained; false if socket would block (OP_WRITE needed) + */ + boolean flushNetOut() throws IOException { + if (netOut.position() == 0) { + return true; + } + netOut.flip(); + while (netOut.hasRemaining()) { + int n = channel.write(netOut); + if (n == 0) { + // socket full; leave netOut in read-mode with leftover, or flip back + // We need netOut in write-mode for next wrap. Compact does that. + netOut.compact(); + return false; + } + } + netOut.clear(); + return true; + } + + /** + * Wrap plaintext into netOut. Caller must subsequently flush via {@link #flushNetOut()}. + * @return bytes consumed from src + */ + int wrap(ByteBuffer src) throws IOException { + if (!handshakeComplete) { + throw new SSLException("Handshake not complete"); + } + int consumed = 0; + while (src.hasRemaining()) { + SSLEngineResult r = engine.wrap(src, netOut); + consumed += r.bytesConsumed(); + Status st = r.getStatus(); + if (st == Status.BUFFER_OVERFLOW) { + // netOut full; caller must flush before continuing + return consumed; + } + if (st == Status.CLOSED) { + throw new SSLException("Engine closed during wrap"); + } + if (r.bytesConsumed() == 0 && r.bytesProduced() == 0) { + break; + } + } + return consumed; + } + + /** + * Called by the event loop when OP_READ fires. Reads socket into netIn and unwraps + * as much as possible into the internal appIn buffer. + * @return bytes of plaintext now available; -1 on EOF + */ + int onReadable() throws IOException { + int n = channel.read(netIn); + if (n < 0) { + eof = true; + return appIn.hasRemaining() ? appIn.remaining() : -1; + } + unwrapAll(); + return appIn.remaining(); + } + + private void unwrapAll() throws IOException { + if (netIn.position() == 0) { + return; + } + // We unwrap into appIn. appIn may have unread plaintext; compact to preserve it. + netIn.flip(); + try { + appIn.compact(); // now write-mode with existing unread bytes preserved + while (netIn.hasRemaining()) { + SSLEngineResult r = engine.unwrap(netIn, appIn); + Status st = r.getStatus(); + if (st == Status.BUFFER_UNDERFLOW) { + break; + } + if (st == Status.BUFFER_OVERFLOW) { + // Grow appIn + ByteBuffer bigger = ByteBuffer.allocate(appIn.capacity() * 2); + appIn.flip(); + bigger.put(appIn); + appIn = bigger; + continue; + } + if (st == Status.CLOSED) { + eof = true; + break; + } + if (r.bytesConsumed() == 0 && r.bytesProduced() == 0) { + break; + } + } + } finally { + netIn.compact(); + appIn.flip(); // back to read mode + } + } + + /** + * Drain decrypted bytes into the caller's buffer. Returns bytes transferred. + */ + int readPlaintext(ByteBuffer dst) { + if (!appIn.hasRemaining()) { + return eof ? -1 : 0; + } + int n = Math.min(appIn.remaining(), dst.remaining()); + int oldLimit = appIn.limit(); + appIn.limit(appIn.position() + n); + dst.put(appIn); + appIn.limit(oldLimit); + return n; + } + + int availablePlaintext() { + return appIn.remaining(); + } + + boolean netOutHasPending() { + return netOut.position() > 0; + } + + void setInterestOps(int ops) { + key.interestOps(ops); + } + + int interestOps() { + return key.interestOps(); + } + + void close() throws IOException { + try { + engine.closeOutbound(); + } catch (Exception ignored) {} + try { + channel.close(); + } finally { + key.cancel(); + } + } +} diff --git a/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/StreamRegistryBenchmark.java b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/StreamRegistryBenchmark.java new file mode 100644 index 0000000000..11cfd144d9 --- /dev/null +++ b/http/http-client/src/jmh/java/software/amazon/smithy/java/http/client/h2/StreamRegistryBenchmark.java @@ -0,0 +1,109 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReferenceArray; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +/** + * Microbenchmark comparing StreamRegistry-style lookup vs ConcurrentHashMap. + * + *

Run with: ./gradlew :http:http-client:jmh -Pjmh.includes="StreamRegistryBenchmark" + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 3, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 2, jvmArgs = {"-Xms1g", "-Xmx1g"}) +@State(Scope.Benchmark) +public class StreamRegistryBenchmark { + + @Param({"10", "100", "1000"}) + private int activeStreams; + + // StreamRegistry-style array lookup + private static final int SLOTS = 4096; + private static final int SLOT_MASK = SLOTS - 1; + private AtomicReferenceArray array; + + // CHM baseline + private ConcurrentHashMap chm; + + private int[] streamIds; + + static final class Entry { + final int streamId; + Entry(int streamId) { + this.streamId = streamId; + } + } + + private static int slot(int streamId) { + return ((streamId - 1) >>> 1) & SLOT_MASK; + } + + private Entry arrayGet(int streamId) { + Entry e = array.get(slot(streamId)); + return (e != null && e.streamId == streamId) ? e : null; + } + + @State(Scope.Thread) + public static class ThreadState { + int index; + } + + @Setup + public void setup() { + array = new AtomicReferenceArray<>(SLOTS); + chm = new ConcurrentHashMap<>(); + streamIds = new int[activeStreams]; + + for (int i = 0; i < activeStreams; i++) { + int streamId = 2 * i + 1; // HTTP/2 client stream IDs: 1, 3, 5, ... + streamIds[i] = streamId; + Entry e = new Entry(streamId); + array.set(slot(streamId), e); + chm.put(streamId, e); + } + } + + @Benchmark + @Threads(1) + public Entry arrayGet_1t(ThreadState ts) { + return arrayGet(streamIds[ts.index++ % activeStreams]); + } + + @Benchmark + @Threads(1) + public Entry chmGet_1t(ThreadState ts) { + return chm.get(streamIds[ts.index++ % activeStreams]); + } + + @Benchmark + @Threads(4) + public Entry arrayGet_4t(ThreadState ts) { + return arrayGet(streamIds[ts.index++ % activeStreams]); + } + + @Benchmark + @Threads(4) + public Entry chmGet_4t(ThreadState ts) { + return chm.get(streamIds[ts.index++ % activeStreams]); + } +} diff --git a/http/http-client/src/jmhServer/java/software/amazon/smithy/java/http/client/BenchmarkServer.java b/http/http-client/src/jmhServer/java/software/amazon/smithy/java/http/client/BenchmarkServer.java index 3629422286..fe14a35890 100644 --- a/http/http-client/src/jmhServer/java/software/amazon/smithy/java/http/client/BenchmarkServer.java +++ b/http/http-client/src/jmhServer/java/software/amazon/smithy/java/http/client/BenchmarkServer.java @@ -40,6 +40,7 @@ import io.netty.handler.codec.http2.Http2HeadersFrame; import io.netty.handler.codec.http2.Http2MultiplexHandler; import io.netty.handler.codec.http2.Http2SecurityUtil; +import io.netty.handler.codec.http2.Http2Settings; import io.netty.handler.codec.http2.Http2StreamFrame; import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ApplicationProtocolNames; @@ -339,7 +340,7 @@ private Channel startH2cServer(int port) throws InterruptedException { .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) { - var settings = io.netty.handler.codec.http2.Http2Settings.defaultSettings() + var settings = Http2Settings.defaultSettings() .maxConcurrentStreams(H2_MAX_CONCURRENT_STREAMS) .initialWindowSize(H2_INITIAL_WINDOW_SIZE) .maxFrameSize(H2_MAX_FRAME_SIZE); @@ -493,7 +494,7 @@ private static class Http2OrHttpHandler extends ApplicationProtocolNegotiationHa @Override protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { if (ApplicationProtocolNames.HTTP_2.equals(protocol)) { - var settings = io.netty.handler.codec.http2.Http2Settings.defaultSettings() + var settings = Http2Settings.defaultSettings() .maxConcurrentStreams(H2_TLS_MAX_CONCURRENT_STREAMS) .initialWindowSize(H2_TLS_INITIAL_WINDOW_SIZE) .maxFrameSize(H2_MAX_FRAME_SIZE); diff --git a/http/http-client/src/main/java/io/netty/channel/epoll/EpollAccess.java b/http/http-client/src/main/java/io/netty/channel/epoll/EpollAccess.java new file mode 100644 index 0000000000..eaec91336f --- /dev/null +++ b/http/http-client/src/main/java/io/netty/channel/epoll/EpollAccess.java @@ -0,0 +1,90 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.netty.channel.epoll; + +import io.netty.channel.unix.FileDescriptor; +import java.io.IOException; + +/** + * Bridge to Netty's epoll internals. Lives in this package only because {@link EpollEventArray} and the + * {@code epollWait(fd, array, int)} overload are package-private; the rest is public {@link Native} API + * re-exported so callers depend on one class. Classpath-only (split package is illegal under JPMS) and + * built on unsupported API, so a Netty upgrade can break it. HTTP client implementation detail. + */ +public final class EpollAccess { + + private EpollAccess() {} + + // --- epoll event flags --- + public static final int EPOLLIN = Native.EPOLLIN; + public static final int EPOLLOUT = Native.EPOLLOUT; + public static final int EPOLLET = Native.EPOLLET; + public static final int EPOLLRDHUP = Native.EPOLLRDHUP; + public static final int EPOLLERR = Native.EPOLLERR; + + // --- epfd / eventfd lifecycle --- + public static FileDescriptor newEpollCreate() { + return Native.newEpollCreate(); + } + + public static FileDescriptor newEventFd() { + return Native.newEventFd(); + } + + public static void eventFdWrite(int fd, long value) { + Native.eventFdWrite(fd, value); + } + + public static void eventFdRead(int fd) { + Native.eventFdRead(fd); + } + + // --- epoll_ctl --- + public static void epollCtlAdd(int efd, int fd, int flags) throws IOException { + Native.epollCtlAdd(efd, fd, flags); + } + + public static void epollCtlMod(int efd, int fd, int flags) throws IOException { + Native.epollCtlMod(efd, fd, flags); + } + + public static void epollCtlDel(int efd, int fd) throws IOException { + Native.epollCtlDel(efd, fd); + } + + /** + * Blocking {@code epoll_wait} into {@code events}. {@code timeoutMillis < 0} waits indefinitely, + * {@code 0} polls. Returns the number of ready descriptors. + */ + public static int epollWait(FileDescriptor epfd, EpollEventArray events, int timeoutMillis) throws IOException { + return Native.epollWait(epfd, events, timeoutMillis); + } + + // --- EpollEventArray (package-private) --- + public static EpollEventArray newEventArray(int length) { + return new EpollEventArray(length); + } + + public static int events(EpollEventArray arr, int index) { + return arr.events(index); + } + + public static int fd(EpollEventArray arr, int index) { + return arr.fd(index); + } + + public static int length(EpollEventArray arr) { + return arr.length(); + } + + public static void increase(EpollEventArray arr) { + arr.increase(); + } + + public static void free(EpollEventArray arr) { + arr.free(); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/DefaultHttpClient.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/DefaultHttpClient.java new file mode 100644 index 0000000000..18513999da --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/DefaultHttpClient.java @@ -0,0 +1,558 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.api.TrailerSupport; +import software.amazon.smithy.java.http.client.connection.ConnectionPool; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * Default {@link HttpClient} implementation. + * + *

Handles connection pooling, interceptors, protocol selection (H1/H2), + * and bidirectional streaming internally. The caller only sees + * {@code send(request) → response}. + */ +final class DefaultHttpClient implements HttpClient { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(DefaultHttpClient.class); + + private final ConnectionPool connectionPool; + private final ProxySelector proxySelector; + private final Duration requestTimeout; + private final List listeners; + private final boolean hasListeners; + private final AtomicLong nextExchangeId = new AtomicLong(); + private final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor(); + + DefaultHttpClient(Builder builder) { + this.connectionPool = builder.connectionPool; + this.proxySelector = builder.proxySelector; + this.requestTimeout = builder.requestTimeout; + this.listeners = builder.resolvedConnectionConfig.listeners(); + this.hasListeners = !listeners.isEmpty(); + } + + @Override + public HttpResponse send(HttpRequest request, RequestOptions options) throws IOException { + Duration timeout = options.requestTimeout() != null ? options.requestTimeout() : requestTimeout; + // The exchange id and the request-ended latch are owned here so the terminal onRequestEnd + // fires exactly once regardless of which path completes the request: + // - success → ManagedResponseBody fires it when the response body is closed + // - failure → the catch below fires it (single owner of final failure, including a + // timeout observed on this caller thread rather than the worker thread) + // A per-route attempt failure inside the proxy loop must NOT end the exchange, since a later + // proxy may still succeed; sendForRoute therefore no longer fires onRequestEnd. + long exchangeId = nextExchangeId.incrementAndGet(); + AtomicBoolean requestEnded = new AtomicBoolean(); + notifyRequestStart(exchangeId, request); + try { + return timeout != null + ? sendWithTimeout(request, options, timeout, exchangeId, requestEnded) + : sendInternal(request, options, exchangeId, requestEnded); + } catch (IOException | RuntimeException e) { + notifyRequestEnd(exchangeId, requestEnded, e); + throw e; + } + } + + private HttpResponse sendInternal( + HttpRequest request, + RequestOptions options, + long exchangeId, + AtomicBoolean requestEnded + ) throws IOException { + var target = request.uri(); + List proxies = proxySelector.select(target); + if (proxies.isEmpty()) { + return sendForRoute(request, options, Route.from(target, null), exchangeId, requestEnded); + } + + IOException last = null; + for (ProxyConfiguration proxy : proxies) { + Route route = Route.from(target, proxy); + try { + return sendForRoute(request, options, route, exchangeId, requestEnded); + } catch (IOException e) { + last = e; + proxySelector.connectFailed(target, proxy, e); + } + } + throw last; + } + + private HttpResponse sendForRoute( + HttpRequest request, + RequestOptions options, + Route route, + long exchangeId, + AtomicBoolean requestEnded + ) throws IOException { + HttpConnection conn = connectionPool.acquire(route, exchangeId, options); + HttpExchange exchange; + try { + exchange = conn.newExchange(request, options); + } catch (Exception e) { + connectionPool.evict(conn, true); + if (e instanceof IOException ioe) { + throw ioe; + } + throw new IOException("Failed to create exchange", e); + } + + try { + // Write request body + DataStream requestBody = request.body(); + boolean hasBody = requestBody != null && requestBody.contentLength() != 0; + + // Set request trailers before writing body so the exchange knows to defer END_STREAM + if (hasBody && requestBody instanceof TrailerSupport ts) { + exchange.setRequestTrailers(ts.trailerHeaders()); + } + + if (hasBody && exchange.supportsBidirectionalStreaming() && !shouldWriteH2BodyInline(requestBody)) { + // H2: write body on background VT for full duplex + final DataStream body = requestBody; + Thread.startVirtualThread(() -> { + try { + exchange.writeRequestBody(body); + } catch (IOException e) { + LOGGER.debug("Error writing request body: {}", e.getMessage()); + } + }); + } else if (hasBody) { + // H1, or replayable bounded H2 bodies: write inline + exchange.writeRequestBody(requestBody); + } else { + // No body, so close request stream to send END_STREAM + exchange.writeRequestBody(null); + } + + // Build response + int statusCode = exchange.responseStatusCode(); + HttpHeaders headers = exchange.responseHeaders(); + HttpVersion version = exchange.responseVersion(); + boolean isH2 = version == HttpVersion.HTTP_2; + String contentType = headers.contentType(); + Long contentLengthValue = headers.contentLength(); + long contentLength = contentLengthValue == null ? -1 : contentLengthValue; + + // Wrap body so close releases connection + DataStream managedBody = new ManagedResponseBody( + exchange, + conn, + isH2, + contentType, + contentLength, + exchangeId, + requestEnded); + + return HttpResponse.create() + .setStatusCode(statusCode) + .setHeaders(headers) + .setHttpVersion(version) + .setBody(managedBody); + } catch (IOException e) { + try { + exchange.close(); + } catch (IOException closeError) { + LOGGER.debug("Error closing exchange after request failure: {}", closeError.getMessage()); + } + connectionPool.evict(conn, true); + // Do not fire onRequestEnd here: a per-route attempt failure may be retried on the next + // proxy, and send() owns the single terminal failure event. + throw e; + } + } + + private static boolean shouldWriteH2BodyInline(DataStream body) { + return body.isReplayable() && body.hasKnownLength(); + } + + /** + * Wraps the response body DataStream to handle connection lifecycle on close. + */ + private final class ManagedResponseBody implements DataStream, TrailerSupport { + private final HttpExchange exchange; + private final HttpConnection conn; + private final boolean isH2; + private final String contentType; + private final long contentLength; + private final long exchangeId; + private final AtomicBoolean requestEnded; + // close()/discard() release or evict the pooled connection; the stream/channel wrappers returned to + // the caller can be closed from a different thread than the one that built the response, so the + // one-shot guard must be atomic to prevent two closers both releasing the same connection. + private final AtomicBoolean closed = new AtomicBoolean(); + private boolean consumed; + // Written by the consuming thread (asInputStream/asChannel/writeTo) and read by close()/discard(), + // which may run on a different thread; volatile so the drain path sees the correct wrapper rather + // than a stale null (which would pick the wrong drain branch and corrupt a reused H1 connection). + private volatile InputStream wrappedStream; + private volatile ReadableByteChannel wrappedChannel; + + ManagedResponseBody( + HttpExchange exchange, + HttpConnection conn, + boolean isH2, + String contentType, + long contentLength, + long exchangeId, + AtomicBoolean requestEnded + ) { + this.exchange = exchange; + this.conn = conn; + this.isH2 = isH2; + this.contentType = contentType; + this.contentLength = contentLength; + this.exchangeId = exchangeId; + this.requestEnded = requestEnded; + } + + @Override + public long contentLength() { + return contentLength; + } + + @Override + public String contentType() { + return contentType; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return !closed.get() && !consumed; + } + + @Override + public InputStream asInputStream() { + markConsumed(); + try { + InputStream inner = exchange.responseBody(); + wrappedStream = inner; + return new ManagedResponseInputStream( + inner, + contentLength, + ManagedResponseBody.this::close, + ManagedResponseBody.this::fail); + } catch (IOException e) { + fail(e); + throw new UncheckedIOException(e); + } + } + + @Override + public ReadableByteChannel asChannel() { + markConsumed(); + try { + ReadableByteChannel inner = exchange.responseBodyChannel(); + wrappedChannel = inner; + return new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + try { + int n = inner.read(dst); + if (n == -1) { + ManagedResponseBody.this.close(); + } + return n; + } catch (IOException e) { + ManagedResponseBody.this.fail(e); + throw e; + } + } + + @Override + public boolean isOpen() { + return inner.isOpen(); + } + + @Override + public void close() throws IOException { + try { + inner.close(); + } finally { + ManagedResponseBody.this.close(); + } + } + }; + } catch (IOException e) { + fail(e); + throw new UncheckedIOException(e); + } + } + + @Override + public void writeTo(OutputStream out) throws IOException { + markConsumed(); + InputStream inner = exchange.responseBody(); + wrappedStream = inner; + try { + inner.transferTo(out); + } catch (IOException e) { + fail(e); + throw e; + } finally { + close(); + } + } + + @Override + public void writeTo(WritableByteChannel ch) throws IOException { + markConsumed(); + InputStream inner = exchange.responseBody(); + wrappedStream = inner; + try { + inner.transferTo(Channels.newOutputStream(ch)); + } catch (IOException e) { + fail(e); + throw e; + } finally { + close(); + } + } + + @Override + public void discard() throws IOException { + if (!closed.compareAndSet(false, true)) { + return; + } + + boolean errored = false; + Throwable error = null; + try { + drainOrDiscardBody(); + } catch (IOException e) { + errored = true; + error = e; + throw e; + } finally { + finishExchange(errored, error); + } + } + + @Override + public void close() { + if (!closed.compareAndSet(false, true)) { + return; + } + + boolean errored = false; + Throwable error = null; + + // H1: drain body for connection reuse. H2: skip, since exchange.close() sends RST_STREAM. + // The body may not have been read at all (wrappedStream == null), e.g. when the + // SDK calls discard() without first opening the stream. In that case we still need + // to drain through the exchange so the H1 keepalive contract is honored; reusing the + // connection without consuming the response body would corrupt the next exchange. + if (!isH2) { + try { + drainOrDiscardBody(); + } catch (IOException e) { + errored = true; + error = e; + } + } + + finishExchange(errored, error); + } + + /** + * Release the response body according to how the caller opened it: drain an opened stream (so an + * H1 keepalive connection is left clean for reuse), close an opened channel, or, if the body was + * never opened, discard it at the exchange level. + */ + private void drainOrDiscardBody() throws IOException { + if (wrappedStream != null) { + wrappedStream.transferTo(OutputStream.nullOutputStream()); + } else if (wrappedChannel != null) { + wrappedChannel.close(); + } else { + exchange.discardResponseBody(); + } + } + + // Close the exchange, then release the connection to the pool (or evict it on error) and fire the + // terminal onRequestEnd. An exception from {@link HttpExchange#close()} marks the exchange errored, + // preserving any earlier error as the reported cause. + private void finishExchange(boolean errored, Throwable error) { + try { + exchange.close(); + } catch (Exception e) { + errored = true; + error = error == null ? e : error; + } + + if (errored) { + connectionPool.evict(conn, true); + } else { + connectionPool.release(conn); + } + + end(error); + } + + @Override + public HttpHeaders trailerHeaders() { + return exchange.responseTrailerHeaders(); + } + + private void markConsumed() { + if (consumed) { + throw new IllegalStateException("DataStream is not replayable and has already been consumed"); + } + consumed = true; + } + + private void end(Throwable error) { + notifyRequestEnd(exchangeId, requestEnded, error); + } + + /** + * Terminal for a failed body read (e.g. an interrupted or errored stream read): close the exchange + * and fire {@code onRequestEnd} with the failure rather than reporting a clean close. + * + *

This evicts the physical connection for both H1 and H2. For H1 that is required: a connection + * abandoned mid-response can't be reused. For H2 it is conservative: a single failed stream only + * strictly needs a RST_STREAM with the connection kept for other/future streams, but we currently + * evict the whole connection rather than implement stream-only recovery. One-shot via the same + * {@code closed} latch as {@link #close()}. + */ + private void fail(Throwable error) { + if (!closed.compareAndSet(false, true)) { + return; + } + try { + exchange.close(); + } catch (Exception ignored) { + // already failing; the original error is the one worth reporting + } + connectionPool.evict(conn, true); + end(error); + } + } + + private HttpResponse sendWithTimeout( + HttpRequest request, + RequestOptions options, + Duration timeout, + long exchangeId, + AtomicBoolean requestEnded + ) throws IOException { + Future future = + executorService.submit(() -> sendInternal(request, options, exchangeId, requestEnded)); + + try { + return future.get(timeout.toMillis(), TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + future.cancel(true); + throw new IOException(String.format( + "Request to `%s` exceeded request timeout of %s seconds", + request.uri().getHost(), + timeout.toSeconds()), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while waiting for HTTP request to complete to `" + + request.uri().getHost() + '`', e); + } catch (ExecutionException e) { + throw unwrap(e); + } + } + + private static IOException unwrap(ExecutionException e) throws IOException { + var cause = e.getCause(); + return switch (cause) { + case IOException io -> throw io; + case RuntimeException re -> throw re; + case Error err -> throw err; + case null -> new IOException("Unexpected exception", e); + default -> new IOException("Unexpected exception", cause); + }; + } + + private void notifyRequestStart(long exchangeId, HttpRequest request) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onRequestStart(exchangeId, request); + } catch (Throwable e) { + listenerFailed("onRequestStart", e); + } + } + } + } + + private void notifyRequestEnd(long exchangeId, AtomicBoolean requestEnded, Throwable error) { + if (hasListeners && requestEnded.compareAndSet(false, true)) { + for (HttpClientListener listener : listeners) { + try { + listener.onRequestEnd(exchangeId, error); + } catch (Throwable e) { + listenerFailed("onRequestEnd", e); + } + } + } + } + + private static void listenerFailed(String event, Throwable error) { + if (error instanceof VirtualMachineError) { + throw (VirtualMachineError) error; + } + LOGGER.warn("HTTP client listener failed in {}", event, error); + } + + @Override + public void close() throws IOException { + executorService.close(); + connectionPool.close(); + } + + @Override + public void shutdown(Duration timeout) { + executorService.shutdown(); + try { + executorService.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + executorService.shutdownNow(); + try { + connectionPool.shutdown(timeout); + } catch (IOException e) { + LOGGER.debug("Error shutting down connection pool: {}", e.getMessage()); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClient.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClient.java new file mode 100644 index 0000000000..08ad08c6e3 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClient.java @@ -0,0 +1,490 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.IOException; +import java.time.Duration; +import java.util.Objects; +import java.util.function.Function; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.client.connection.ConnectionConfig; +import software.amazon.smithy.java.http.client.connection.ConnectionPool; +import software.amazon.smithy.java.http.client.connection.HttpConnectionPool; +import software.amazon.smithy.java.http.client.connection.HttpSocketFactory; +import software.amazon.smithy.java.http.client.connection.HttpVersionPolicy; +import software.amazon.smithy.java.http.client.connection.TlsProvider; +import software.amazon.smithy.java.http.client.dns.DnsResolver; + +/** + * Blocking, virtual-thread-friendly HTTP client. + */ +public interface HttpClient extends AutoCloseable { + /** + * Sends a request and returns a streaming response. + * + *

The response body streams directly from the socket. The caller must close the response body + * when done to release the connection back to the pool. + * + *

For HTTP/2, the request body is written concurrently with reading the response (full duplex). + * For HTTP/1.1, the request body is fully sent before the response is returned. + * + * @param request the HTTP request to send + * @return the HTTP response with streaming body + * @throws IOException if the request fails + */ + default HttpResponse send(HttpRequest request) throws IOException { + return send(request, RequestOptions.defaults()); + } + + /** + * Send a request with request options. + * + * @param request request to send. + * @param options options to apply. + * @return the HTTP response + * @throws IOException if the request fails + */ + HttpResponse send(HttpRequest request, RequestOptions options) throws IOException; + + /** + * Closes the client and its underlying connection pool. + */ + @Override + void close() throws IOException; + + /** + * Gracefully shuts down the client, waiting for in-flight requests to complete. + * + * @param timeout maximum time to wait for in-flight requests to complete + */ + void shutdown(Duration timeout); + + /** + * Builder to create a new default HTTP client. + */ + static Builder builder() { + return new Builder(); + } + + /** + * Builder used to create a default HTTP client implementation. + */ + final class Builder { + private static final ProxySelector DIRECT = ProxySelector.direct(); + private final ConnectionConfig.Builder connectionConfig = ConnectionConfig.builder(); + Function connectionPoolFactory = HttpConnectionPool::new; + Duration requestTimeout; + ProxySelector proxySelector = DIRECT; + ConnectionConfig resolvedConnectionConfig; + ConnectionPool connectionPool; + + private Builder() {} + + /** + * Set a custom connection pool factory. + * + *

The factory receives the final immutable connection configuration, including listeners registered on this + * client builder. This keeps request-level and connection-level listener events wired consistently for custom + * pools. + * + * @param factory the connection pool factory to use + * @return this builder + */ + public Builder connectionPoolFactory(Function factory) { + this.connectionPoolFactory = Objects.requireNonNull(factory, "connectionPoolFactory"); + return this; + } + + /** + * Set total request timeout (default: none). + * + *

If set, the entire buffered request must complete within this duration, or an {@link IOException} is + * thrown. Timeout is not enforced for streaming responses as control flow is handed back to the caller. + * + *

If not set (null), requests have no overall timeout and are only limited by + * the connect and read timeouts. + * + * @param timeout total request timeout duration, or null for no timeout + * @return this builder + * @throws IllegalArgumentException if timeout is negative or zero + */ + public Builder requestTimeout(Duration timeout) { + if (timeout != null && (timeout.isNegative() || timeout.isZero())) { + throw new IllegalArgumentException("requestTimeout must be positive or null: " + timeout); + } + this.requestTimeout = timeout; + return this; + } + + /** + * Set proxy configuration for all connections made by this client. + * + *

When configured, all HTTP requests will be routed through the proxy unless the target host matches + * one of the non-proxy hosts. + * + *

For HTTPS requests, the client establishes a CONNECT tunnel through the proxy, then performs TLS + * handshake through the tunnel. + * + *

For HTTP requests, the client connects to the proxy and sends requests with absolute URIs. + * + * @param proxy the proxy configuration, or null for direct connections + * @return this builder + * @see ProxyConfiguration + */ + public Builder proxy(ProxyConfiguration proxy) { + return proxySelector(proxy != null ? ProxySelector.of(proxy) : DIRECT); + } + + /** + * Set a custom proxy selector for dynamic proxy selection. + * + *

The selector is called for each request and can return multiple proxies to try in order. + * If a proxy fails, the next one is attempted. + * + * @param selector the proxy selector to use + * @return this builder + */ + public Builder proxySelector(ProxySelector selector) { + this.proxySelector = Objects.requireNonNull(selector, "proxySelector"); + return this; + } + + /** + * Add a listener for HTTP client lifecycle events. + * + *

Listeners are invoked synchronously on the thread performing the work. Implementations should avoid + * blocking and keep allocation low. + * + * @param listener listener to add + * @return this builder + */ + public Builder addListener(HttpClientListener listener) { + connectionConfig.addListener(listener); + return this; + } + + /** + * Add a listener at the front of the listener list. + * + * @param listener listener to add + * @return this builder + */ + public Builder addListenerFirst(HttpClientListener listener) { + connectionConfig.addListenerFirst(listener); + return this; + } + + /** + * Set the maximum number of connections per route (scheme + host + port + proxy). Default: 256. + * + *

For HTTP/2 this caps the connections opened to a route before streams are multiplexed onto + * existing connections; for HTTP/1.1 it caps the pooled connections per route. + * + * @param max maximum connections per route (must be positive) + * @return this builder + */ + public Builder maxConnectionsPerRoute(int max) { + connectionConfig.maxConnectionsPerRoute(max); + return this; + } + + /** + * Set the maximum number of open physical connections across all routes. Default: 256. + * + *

When the limit is reached, acquiring a connection blocks for up to {@link #acquireTimeout}. + * Must be greater than or equal to {@link #maxConnectionsPerRoute}. + * + * @param max maximum total connections (must be positive) + * @return this builder + */ + public Builder maxTotalConnections(int max) { + connectionConfig.maxTotalConnections(max); + return this; + } + + /** + * Set how long an idle pooled connection is kept before the background cleanup closes it. + * Default: 2 minutes. + * + * @param duration maximum idle time (must be positive) + * @return this builder + */ + public Builder maxIdleTime(Duration duration) { + connectionConfig.maxIdleTime(duration); + return this; + } + + /** + * Set how long {@code acquire} blocks waiting for capacity when the pool is exhausted before + * failing with an {@link IOException}. Default: 30 seconds. {@link Duration#ZERO} fails fast. + * + * @param timeout acquire timeout (must be non-negative) + * @return this builder + */ + public Builder acquireTimeout(Duration timeout) { + connectionConfig.acquireTimeout(timeout); + return this; + } + + /** + * Set the TCP connect timeout for establishing a new socket. Default: 10 seconds. + * + * @param timeout connect timeout (must be non-negative) + * @return this builder + */ + public Builder connectTimeout(Duration timeout) { + connectionConfig.connectTimeout(timeout); + return this; + } + + /** + * Set the timeout for completing the TLS handshake on a new secure connection. Default: 10 seconds. + * + * @param timeout TLS negotiation timeout (must be non-negative) + * @return this builder + */ + public Builder tlsNegotiationTimeout(Duration timeout) { + connectionConfig.tlsNegotiationTimeout(timeout); + return this; + } + + /** + * Set the read timeout applied to each socket read while receiving a response. Default: 30 seconds. + * + * @param timeout read timeout (must be non-negative) + * @return this builder + */ + public Builder readTimeout(Duration timeout) { + connectionConfig.readTimeout(timeout); + return this; + } + + /** + * Set the write timeout applied while sending a request body. Default: 30 seconds. + * + * @param timeout write timeout (must be non-negative) + * @return this builder + */ + public Builder writeTimeout(Duration timeout) { + connectionConfig.writeTimeout(timeout); + return this; + } + + /** + * Sets the {@link SSLContext} for the JDK TLS path. When null, {@link SSLContext#getDefault()} + * is used. + * + *

This configures the built-in JDK provider and is convenience equivalent to + * {@code tlsProvider(JdkTlsProvider.builder().sslContext(context).build())}. It governs: + *

    + *
  • the default (JDK) TLS connection to the target, when no custom + * {@link #tlsProvider(TlsProvider)} is set; and
  • + *
  • the HTTP/1.1-only {@code SSLSocket} fast path.
  • + *
+ * + *

It is ignored for the target connection when a custom {@link #tlsProvider} is set + * (that provider supplies its own TLS configuration). + * + *

HTTPS proxies: the TLS connection to an {@code https} proxy always uses this + * context (and {@link #sslParameters}), independent of {@link #tlsProvider}: a custom provider + * applies only to the end-to-end connection through the tunnel, not to the proxy leg. To trust a + * proxy differently from the target, set a context here that covers both. + * + * @param context the SSL context, or null for the JDK default + * @return this builder + */ + public Builder sslContext(SSLContext context) { + connectionConfig.sslContext(context); + return this; + } + + /** + * Sets {@link SSLParameters} (cipher suites, protocols, SNI, etc.) for the JDK TLS path. When + * null, parameters derived from the {@link #sslContext} are used. + * + *

Convenience equivalent to + * {@code tlsProvider(JdkTlsProvider.builder().sslParameters(params).build())}. Applies to the + * same connections as {@link #sslContext} (the JDK target path, the HTTP/1.1 {@code SSLSocket} + * fast path, and the {@code https}-proxy leg), and is likewise ignored for the target connection + * when a custom {@link #tlsProvider} is set. + * + * @param parameters the SSL parameters, or null for defaults + * @return this builder + */ + public Builder sslParameters(SSLParameters parameters) { + connectionConfig.sslParameters(parameters); + return this; + } + + /** + * Select the TLS provider used for secure connections, replacing the built-in JDK provider. + * + *

A provider turns a connected socket into a handshaken transport; it need not be based on a + * {@code javax.net.ssl.SSLEngine}. This is the provider-neutral way to choose a TLS + * implementation (e.g. a native stack). + * + *

An explicit provider set here always takes precedence. When none is set, a provider may be + * selected by the {@value TlsProvider#PROVIDER_PROPERTY} system property (set to a registered + * provider's fully-qualified class name); otherwise the JDK provider is used. Merely having a + * provider module on the classpath does not engage it; the property is the opt-in. + * + * @param provider the TLS provider, or null to use property selection / the JDK provider + * @return this builder + */ + public Builder tlsProvider(TlsProvider provider) { + connectionConfig.tlsProvider(provider); + return this; + } + + /** + * Set the HTTP version policy (e.g. negotiate via ALPN, enforce HTTP/1.1, enforce HTTP/2, + * h2c prior knowledge). Default: {@link HttpVersionPolicy#AUTOMATIC}. + * + * @param policy the version policy (must not be null) + * @return this builder + */ + public Builder httpVersionPolicy(HttpVersionPolicy policy) { + connectionConfig.httpVersionPolicy(policy); + return this; + } + + /** + * Set the DNS resolver used to resolve hostnames to addresses. When null, a default round-robin + * resolver is used. + * + * @param resolver the DNS resolver (must not be null) + * @return this builder + */ + public Builder dnsResolver(DnsResolver resolver) { + connectionConfig.dnsResolver(resolver); + return this; + } + + /** + * Set a custom factory for creating the underlying {@link java.net.Socket}, honored verbatim. + * When not set, sockets are created with the library defaults plus any + * {@link #socketReceiveBufferSize(int)}/{@link #socketSendBufferSize(int)} knobs. + * + * @param socketFactory the socket factory (must not be null) + * @return this builder + */ + public Builder socketFactory(HttpSocketFactory socketFactory) { + connectionConfig.socketFactory(socketFactory); + return this; + } + + /** + * Set the socket receive buffer size ({@code SO_RCVBUF}) in bytes. Unset by default (kernel + * default); {@code -1} requests kernel autotuning. Ignored when a custom + * {@link #socketFactory(HttpSocketFactory)} is supplied. + * + * @param bytes receive buffer size in bytes (positive, or -1 for autotune) + * @return this builder + */ + public Builder socketReceiveBufferSize(int bytes) { + connectionConfig.socketReceiveBufferSize(bytes); + return this; + } + + /** + * Set the socket send buffer size ({@code SO_SNDBUF}) in bytes. Unset by default (kernel + * default); {@code -1} requests kernel autotuning. Ignored when a custom + * {@link #socketFactory(HttpSocketFactory)} is supplied. + * + * @param bytes send buffer size in bytes (positive, or -1 for autotune) + * @return this builder + */ + public Builder socketSendBufferSize(int bytes) { + connectionConfig.socketSendBufferSize(bytes); + return this; + } + + /** + * Set the application-side read buffer size for the TLS engine transport, in bytes. Default: 16 KiB. + * Larger buffers reduce read syscalls for bulk downloads. + * + * @param bytes TLS read buffer size in bytes (must be positive) + * @return this builder + */ + public Builder tlsReadBufferSize(int bytes) { + connectionConfig.tlsReadBufferSize(bytes); + return this; + } + + /** + * Set the application-side write buffer size for the TLS engine transport, in bytes. Default: 16 KiB. + * Larger buffers can coalesce write syscalls for bulk uploads. + * + * @param bytes TLS write buffer size in bytes (must be positive) + * @return this builder + */ + public Builder tlsWriteBufferSize(int bytes) { + connectionConfig.tlsWriteBufferSize(bytes); + return this; + } + + /** + * Set the HTTP/2 initial stream flow-control window advertised to the peer, in bytes. Default: 65535. + * + * @param windowSize initial window size in bytes (must be positive) + * @return this builder + */ + public Builder h2InitialWindowSize(int windowSize) { + connectionConfig.h2InitialWindowSize(windowSize); + return this; + } + + /** + * Set the HTTP/2 maximum frame size advertised to the peer, in bytes. Default: 16384. Must be + * between 16384 and 16777215 inclusive (per RFC 9113). + * + * @param frameSize maximum frame size in bytes (16384..16777215) + * @return this builder + */ + public Builder h2MaxFrameSize(int frameSize) { + connectionConfig.h2MaxFrameSize(frameSize); + return this; + } + + /** + * Set the maximum number of concurrent HTTP/2 streams to multiplex per connection. Default: 100. + * + * @param streams maximum concurrent streams per connection (must be positive) + * @return this builder + */ + public Builder h2StreamsPerConnection(int streams) { + connectionConfig.h2StreamsPerConnection(streams); + return this; + } + + /** + * Set the HTTP/2 connection I/O buffer size in bytes. Default: 256 KiB. Must be at least 16 KiB. + * + * @param bufferSize I/O buffer size in bytes (at least 16384) + * @return this builder + */ + public Builder h2BufferSize(int bufferSize) { + connectionConfig.h2BufferSize(bufferSize); + return this; + } + + /** + * Build the HTTP client. + * + * @return a new HTTP client instance + */ + public HttpClient build() { + resolvedConnectionConfig = connectionConfig.build(); + connectionPool = Objects.requireNonNull( + connectionPoolFactory.apply(resolvedConnectionConfig), + "connectionPoolFactory returned null"); + return new DefaultHttpClient(this); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClientListener.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClientListener.java new file mode 100644 index 0000000000..f5eaaa1530 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpClientListener.java @@ -0,0 +1,184 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.net.InetAddress; +import java.util.List; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.client.connection.CloseReason; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.Route; + +/** + * Listener for HTTP client lifecycle events. + * + *

Listener methods are invoked synchronously on the thread performing the work. Implementations should avoid + * blocking and keep allocation low. + * + *

Unclosed response bodies and the leak signal

+ *

For a successful response, {@link #onRequestEnd} fires when the caller closes, discards, or fully consumes the + * response body. If the caller drops the response without doing any of these, the underlying connection is leaked + * (never released to the pool) and {@code onRequestEnd} is intentionally never fired. A request with + * an {@link #onRequestStart} and no matching {@code onRequestEnd} is therefore the canonical signal that a response + * body was leaked (the missing event is not a defect, it is how a leak is detected). The client does not fire a late + * {@code onRequestEnd} from a finalizer/{@link java.lang.ref.Cleaner}, because doing so would report a leak as a + * normal (and wildly mis-timed) completion and corrupt any duration metric. + * + *

Consequently, a listener that opens per-exchange state on {@code onRequestStart} (a span, an in-flight gauge, a + * timer) and only releases it on {@code onRequestEnd} will itself leak that state when a caller abandons a response. + * Such listeners must bound their own state independently (a TTL, a max-in-flight cap, or periodic sweeping); the + * framework does not guarantee a terminal event for an abandoned response. + */ +public interface HttpClientListener { + /** + * Called before a request starts. + * + * @param exchangeId opaque client-generated exchange id + * @param request request being sent + */ + default void onRequestStart(long exchangeId, HttpRequest request) {} + + /** + * Called when a request reaches terminal disposition. + * + *

For streaming responses, this fires when the response body is closed, discarded, fully consumed, or errors. + * For failures before a response body exists, this fires when the failure is observed. It fires at most once per + * exchange. + * + *

This event is not guaranteed: if the caller abandons a successful response without closing + * or consuming its body, the connection leaks and this event never fires. See the class documentation for how + * that absence serves as the leak signal. + * + * @param exchangeId opaque client-generated exchange id + * @param error failure, or null on success + */ + default void onRequestEnd(long exchangeId, Throwable error) {} + + /** + * Called before resolving a hostname. + * + * @param exchangeId opaque client-generated exchange id + * @param host hostname to resolve + */ + default void onDnsStart(long exchangeId, String host) {} + + /** + * Called after DNS resolution completes or fails. + * + * @param exchangeId opaque client-generated exchange id + * @param host hostname resolved + * @param addresses resolved addresses, never null; empty when resolution failed before producing results + * @param error failure, or null on success + */ + default void onDnsEnd(long exchangeId, String host, List addresses, Throwable error) {} + + /** + * Called before opening a TCP connection. + * + * @param exchangeId opaque client-generated exchange id + * @param route route being connected + * @param address address being connected + */ + default void onConnectStart(long exchangeId, Route route, InetAddress address) {} + + /** + * Called after a TCP connection succeeds or fails. + * + * @param exchangeId opaque client-generated exchange id + * @param route route being connected + * @param address address being connected + * @param error failure, or null on success + */ + default void onConnectEnd(long exchangeId, Route route, InetAddress address, Throwable error) {} + + /** + * Called before TLS negotiation with the origin server starts. + * + *

For requests through an HTTPS proxy, this event does not cover the client-to-proxy TLS hop; it + * only covers origin (target) TLS, if any. + * + * @param exchangeId opaque client-generated exchange id + * @param route route being negotiated + */ + default void onTlsStart(long exchangeId, Route route) {} + + /** + * Called after TLS negotiation with the origin server succeeds or fails. + * + *

For requests through an HTTPS proxy, this event does not cover the client-to-proxy TLS hop; it + * only covers origin (target) TLS, if any. + * + * @param exchangeId opaque client-generated exchange id + * @param route route being negotiated + * @param protocol ALPN protocol, or null when none was negotiated + * @param cipherSuite TLS cipher suite, or null when unavailable + * @param error failure, or null on success + */ + default void onTlsEnd(long exchangeId, Route route, String protocol, String cipherSuite, Throwable error) {} + + /** + * Called before sending an HTTP CONNECT request to a proxy. + * + * @param exchangeId opaque client-generated exchange id + * @param route target route + * @param proxy proxy configuration + * @param address proxy address being used + */ + default void onProxyConnectStart(long exchangeId, Route route, ProxyConfiguration proxy, InetAddress address) {} + + /** + * Called after an HTTP CONNECT request to a proxy completes or fails. + * + *

A CONNECT that returns a non-2xx status is a tunnel failure: {@code error} is non-null and + * {@code statusCode} carries the rejected status. {@code error} is null only when the tunnel was + * established successfully. + * + * @param exchangeId opaque client-generated exchange id + * @param route target route + * @param proxy proxy configuration + * @param address proxy address being used + * @param statusCode proxy response status, or -1 if no response was received + * @param error failure, or null on success + */ + default void onProxyConnectEnd( + long exchangeId, + Route route, + ProxyConfiguration proxy, + InetAddress address, + int statusCode, + Throwable error + ) {} + + /** + * Called after a connection is established and assigned to the pool. + * + * @param connection established connection + */ + default void onConnectionCreated(HttpConnection connection) {} + + /** + * Called when a connection is acquired. + * + * @param connection acquired connection + * @param reused true if the connection was reused + */ + default void onConnectionAcquired(HttpConnection connection, boolean reused) {} + + /** + * Called when a connection is returned to the pool. + * + * @param connection returned connection + */ + default void onConnectionReturned(HttpConnection connection) {} + + /** + * Called when a connection is closed by the pool. + * + * @param connection closed connection + * @param reason close reason + */ + default void onConnectionClosed(HttpConnection connection, CloseReason reason) {} +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpCredentials.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpCredentials.java new file mode 100644 index 0000000000..ae654af483 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpCredentials.java @@ -0,0 +1,107 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; +import java.util.Objects; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.ModifiableHttpRequest; + +/** + * Credentials for HTTP authentication. + * + *

Implementations handle both preemptive auth (e.g., Basic, Bearer) and challenge-response auth (e.g., + * Digest, NTLM, Negotiate). + * + *

Used for both proxy authentication (CONNECT requests) and server authentication (normal requests). + */ +public interface HttpCredentials { + /** + * Apply authentication to an HTTP request. + * + *

Called before sending the request (preemptive), and again if a 401/407 challenge is received (reactive). + * Implementations can handle multi-round handshakes by tracking state internally. + * + * @param request the modifiable request to add auth headers to + * @param priorResponse null on first call, or the 401/407 response for reactive auth + * @return true if auth was applied and should retry, false to give up + */ + boolean authenticate(ModifiableHttpRequest request, HttpResponse priorResponse); + + /** + * HTTP Basic authentication credentials. + * + *

Sends credentials preemptively in the Authorization or Proxy-Authorization header. + * + * @param username Username to send. + * @param password Password to send. + * @param forProxy True if this is for Proxy-Authorization, false for Authorization. + */ + record Basic(String username, String password, boolean forProxy) implements HttpCredentials { + + public Basic { + Objects.requireNonNull(username, "username"); + Objects.requireNonNull(password, "password"); + } + + /** + * Create Basic credentials for server authentication. + */ + public Basic(String username, String password) { + this(username, password, false); + } + + @Override + public boolean authenticate(ModifiableHttpRequest request, HttpResponse priorResponse) { + // Basic auth is preemptive. If we already tried and got a challenge, give up. + if (priorResponse != null) { + return false; + } + + String credentials = Base64.getEncoder() + .encodeToString((username + ':' + password).getBytes(StandardCharsets.UTF_8)); + String header = forProxy ? "Proxy-Authorization" : "Authorization"; + request.setHeader(header, List.of("Basic " + credentials)); + return true; + } + } + + /** + * HTTP Bearer token authentication (RFC 6750). + * + *

Sends the token preemptively in the Authorization or Proxy-Authorization header. + * The token is sent as-is (no encoding applied). + * + * @param token Bearer token. Sent as-is on the wire. + * @param forProxy True if this is for Proxy-Authorization, false for Authorization. + */ + record Bearer(String token, boolean forProxy) implements HttpCredentials { + + public Bearer { + Objects.requireNonNull(token, "token"); + } + + /** + * Create Bearer credentials for server authentication. + */ + public Bearer(String token) { + this(token, false); + } + + @Override + public boolean authenticate(ModifiableHttpRequest request, HttpResponse priorResponse) { + if (priorResponse != null) { + return false; + } + + String header = forProxy ? "Proxy-Authorization" : "Authorization"; + request.setHeader(header, List.of("Bearer " + token)); + return true; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpExchange.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpExchange.java new file mode 100644 index 0000000000..fa0eb661d1 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/HttpExchange.java @@ -0,0 +1,208 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * HTTP request/response exchange. + * + *

Lifecycle: + * The exchange automatically closes when both the request and response streams are closed. + * Using try-with-resources on the exchange is recommended as a safety net, but not strictly required if both streams + * are properly closed. The {@link #close()} method of an HttpExchange implementation MUST be idempotent and ignore + * successive calls to close(). + * + *

Protocol-Specific Behavior: + *

    + *
  • HTTP/1.1: Sequential only. Request body must be fully written and closed before response can be read. + * True bidirectional streaming is NOT supported. Not thread-safe.
  • + *
  • HTTP/2: Full bidirectional streaming. Can read response while writing request. + * Thread-safe for concurrent read/write from separate threads.
  • + *
+ * + *

Usage Pattern with try-with-resources (recommended): + * {@snippet : + * try (HttpExchange exchange = client.newExchange(request)) { + * exchange.writeRequestBody(request.body()); + * int status = exchange.responseStatusCode(); + * try (InputStream in = exchange.responseBody()) { + * byte[] body = in.readAllBytes(); + * } + * } + * } + */ +public interface HttpExchange extends AutoCloseable { + /** + * Returns the HTTP request associated with this exchange. + * + *

For exchanges created by {@link HttpClient}, this returns the request after + * interceptors have been applied (the "effective" request). + * + * @return the HTTP request + */ + HttpRequest request(); + + /** + * Write the given request body to the exchange. + * + * @param body the body to write + * @throws IOException if an I/O error occurs + */ + void writeRequestBody(DataStream body) throws IOException; + + /** + * HTTP version from response. Blocks until received. + * + *

For HTTP/1.x connections, this returns the version from the response + * status line (HTTP/1.0 or HTTP/1.1). For HTTP/2, always returns HTTP/2. + * + * @return HTTP response version + */ + HttpVersion responseVersion() throws IOException; + + /** + * Response status code. Blocks until received. + * + *

IMPORTANT: On HTTP/1.1, this will block until the request body + * is fully written and closed. + * + * @return response status code + */ + int responseStatusCode() throws IOException; + + /** + * Read from response body. Blocks until data available. + * + *

IMPORTANT: On HTTP/1.1, this will block until the request body + * is fully written and closed. True bidirectional streaming requires HTTP/2. + * + *

Closing this stream will automatically close the exchange for HTTP/1.1. For HTTP/2, closing this stream + * while the request stream is also closed will automatically close the exchange. + * + * {@snippet : + * try (InputStream in = exchange.responseBody()) { + * byte[] body = in.readAllBytes(); + * } + * } + * + * @return the response input stream to read. + */ + InputStream responseBody() throws IOException; + + /** + * Drain and discard the response body while preserving connection reuse when possible. + * + *

The default implementation uses {@link #responseBody()}. Protocol-specific implementations can override + * this to avoid constructing generic stream adapters for common response forms. + * + * @throws IOException if an I/O error occurs + */ + default void discardResponseBody() throws IOException { + responseBody().transferTo(OutputStream.nullOutputStream()); + } + + /** + * Get a readable byte channel for the response body. + * + *

Default wraps {@link #responseBody()} via Channels.newChannel(). H2 exchanges override this to return a + * native channel that avoids intermediate byte[] copies. + * + * @return a readable byte channel for the response body + */ + default ReadableByteChannel responseBodyChannel() throws IOException { + return Channels.newChannel(responseBody()); + } + + /** + * Response headers. Blocks until received. + * + *

IMPORTANT: On HTTP/1.1, this will block until the request body is fully written and closed. + * + * @return HTTP response headers. + */ + HttpHeaders responseHeaders() throws IOException; + + /** + * Get trailer headers if any were received. + * + *

Trailers are headers sent after the message body. They are supported in: + *

    + *
  • HTTP/1.1: Via chunked transfer encoding
  • + *
  • HTTP/2: Via HEADERS frame after DATA with END_STREAM
  • + *
+ * + *

Important: Trailers are only available after the entire response body has been read. + * Calling this before the body is fully consumed returns null. + * + * {@snippet : + * try (InputStream in = exchange.responseBody()) { + * in.readAllBytes(); // must fully consume body first + * } + * + * HttpHeaders trailers = exchange.responseTrailerHeaders(); + * if (trailers != null) { + * String checksum = trailers.firstValue("checksum").orElse(null); + * } + * } + * + * @return trailer headers, or null if no trailers were received + */ + default HttpHeaders responseTrailerHeaders() { + return null; + } + + /** + * Check if this exchange supports true bidirectional streaming. + * + *

If false (e.g., HTTP/1.1), the request body must be fully written and closed before + * attempting to read the response. + * + * @return true if the exchange supports bidirectional streaming. + */ + default boolean supportsBidirectionalStreaming() { + return false; + } + + /** + * Set trailer headers to be sent after the request body. + * + *

Must be called before closing the request body stream. Trailers are supported in: + *

    + *
  • HTTP/1.1: Only with chunked transfer encoding
  • + *
  • HTTP/2: Always supported
  • + *
+ * + *

Example usage: + * {@snippet : + * HttpExchange exchange = connection.newExchange(request); + * exchange.setRequestTrailers(HttpHeaders.of(Map.of("checksum", List.of("abc123")))); + * exchange.writeRequestBody(DataStream.ofBytes(data)); // trailers sent after the body + * } + * + * @param trailers the trailer headers to send + * @throws IllegalStateException if trailers are not supported (e.g., H1 without chunked encoding) + */ + default void setRequestTrailers(HttpHeaders trailers) { + throw new UnsupportedOperationException("Request trailers not supported"); + } + + /** + * {@inheritDoc} + * + *

This method is idempotent and may be called multiple times safely. + */ + @Override + void close() throws IOException; +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ManagedResponseInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ManagedResponseInputStream.java new file mode 100644 index 0000000000..339eab2bf5 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ManagedResponseInputStream.java @@ -0,0 +1,217 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.function.Consumer; + +/** + * InputStream wrapper that preserves optimized bulk operations and releases response lifecycle on EOF or close. + */ +final class ManagedResponseInputStream extends InputStream { + // Cap for the pre-sized readAllBytes path: a (possibly untrusted) Content-Length above this + // falls back to the JDK grow-as-you-go path rather than pre-allocating a huge buffer up front. + private static final int MAX_PRESIZED_LEN = 64 * 1024 * 1024; + + private final InputStream inner; + private final Runnable onClose; + private final Consumer onError; + private long remaining; + + ManagedResponseInputStream(InputStream inner, long contentLength, Runnable onClose) { + this(inner, contentLength, onClose, ignored -> {}); + } + + ManagedResponseInputStream(InputStream inner, long contentLength, Runnable onClose, Consumer onError) { + this.inner = inner; + this.onClose = onClose; + this.onError = onError; + this.remaining = contentLength >= 0 ? contentLength : -1; + } + + /** Run the error terminal for a read that threw, then rethrow. */ + private T failed(T e) { + onError.accept(e); + return e; + } + + @Override + public int read() throws IOException { + int b; + try { + b = inner.read(); + } catch (IOException e) { + throw failed(e); + } + if (b == -1) { + onClose.run(); + } else { + bytesRead(1); + } + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int n; + try { + n = inner.read(b, off, len); + } catch (IOException e) { + throw failed(e); + } + if (n == -1) { + onClose.run(); + } else { + bytesRead(n); + } + return n; + } + + @Override + public byte[] readAllBytes() throws IOException { + byte[] result; + try { + long len = remaining; + result = (len >= 0 && len <= MAX_PRESIZED_LEN) ? readKnownLength((int) len) : inner.readAllBytes(); + } catch (IOException e) { + // A failed (e.g. interrupted) read must NOT fire the success terminal. That would report a + // clean completion (onRequestEnd(null)) for a torn read and pool a broken connection. + throw failed(e); + } + onClose.run(); + return result; + } + + // Caller (readAllBytes) routes a thrown read through failed(); no terminal here. + private byte[] readKnownLength(int len) throws IOException { + byte[] buf = new byte[len]; + int pos = 0; + while (pos < len) { + int n = inner.read(buf, pos, len - pos); + if (n < 0) { + return Arrays.copyOf(buf, pos); // stream ended early; trim to what we read + } + pos += n; + } + return buf; + } + + @Override + public byte[] readNBytes(int len) throws IOException { + byte[] bytes; + try { + bytes = inner.readNBytes(len); + } catch (IOException e) { + throw failed(e); + } + if (bytes.length < len) { + onClose.run(); + } + bytesRead(bytes.length); + return bytes; + } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + int n; + try { + n = inner.readNBytes(b, off, len); + } catch (IOException e) { + throw failed(e); + } + if (n < len) { + onClose.run(); + } + bytesRead(n); + return n; + } + + @Override + public long transferTo(OutputStream out) throws IOException { + long n; + try { + n = inner.transferTo(out); + } catch (IOException e) { + throw failed(e); + } + onClose.run(); + return n; + } + + @Override + public long skip(long n) throws IOException { + long skipped; + try { + skipped = inner.skip(n); + } catch (IOException e) { + throw failed(e); + } + bytesRead(skipped); + return skipped; + } + + @Override + public void skipNBytes(long n) throws IOException { + try { + inner.skipNBytes(n); + bytesRead(n); + } catch (IOException e) { + throw failed(e); + } + } + + @Override + public int available() throws IOException { + try { + return inner.available(); + } catch (IOException e) { + throw failed(e); + } + } + + @Override + public boolean markSupported() { + return inner.markSupported(); + } + + @Override + public synchronized void mark(int readlimit) { + inner.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + try { + inner.reset(); + } catch (IOException e) { + throw failed(e); + } + } + + @Override + public void close() throws IOException { + try { + inner.close(); + } catch (IOException e) { + // Throw to evict + throw failed(e); + } + onClose.run(); + } + + private void bytesRead(long n) { + if (remaining < 0 || n <= 0) { + return; + } + remaining -= n; + if (remaining <= 0) { + onClose.run(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxyConfiguration.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxyConfiguration.java new file mode 100644 index 0000000000..1a66c5fc2e --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxyConfiguration.java @@ -0,0 +1,96 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.util.Objects; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Proxy configuration for HTTP connections. + * + *

Currently supports HTTP proxies (CONNECT tunnel for HTTPS targets). + * SOCKS proxy types are defined but not yet implemented. + * + * @param proxyUri Proxy server URI. + * @param type Type of proxy. + * @param credentials Optional credentials for proxy authentication. + */ +public record ProxyConfiguration(SmithyUri proxyUri, ProxyType type, HttpCredentials credentials) { + /** + * Create a proxy configuration without authentication. + * + * @param proxyUri proxy server URI + * @param type proxy type + */ + public ProxyConfiguration(SmithyUri proxyUri, ProxyType type) { + this(proxyUri, type, null); + } + + public ProxyConfiguration { + Objects.requireNonNull(proxyUri, "proxyUri cannot be null"); + Objects.requireNonNull(type, "type cannot be null"); + } + + /** + * Create a proxy configuration with Basic authentication. + * + * @param proxyUri proxy server URI + * @param type proxy type + * @param username authentication username + * @param password authentication password + * @return proxy configuration with Basic auth credentials + */ + public static ProxyConfiguration withBasicAuth( + SmithyUri proxyUri, + ProxyType type, + String username, + String password + ) { + return new ProxyConfiguration(proxyUri, type, new HttpCredentials.Basic(username, password, true)); + } + + /** + * Returns the proxy hostname. + * + * @return the hostname from the proxy URI + */ + public String hostname() { + return proxyUri.getHost(); + } + + /** + * Returns the proxy port. + * + *

If the port is not specified in the URI, returns the default port + * for the proxy type: 8080 for HTTP/HTTPS, 1080 for SOCKS. + * + * @return the proxy port + */ + public int port() { + int port = proxyUri.getPort(); + if (port != -1) { + return port; + } + return switch (type) { + case HTTP -> 8080; + case SOCKS4, SOCKS5 -> 1080; + }; + } + + /** + * Proxy protocol type. + */ + public enum ProxyType { + /** HTTP proxy (CONNECT tunnel for HTTPS targets) */ + HTTP, + + /** SOCKS4 proxy */ + SOCKS4, + + /** SOCKS5 proxy */ + SOCKS5 + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxySelector.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxySelector.java new file mode 100644 index 0000000000..87d71af297 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/ProxySelector.java @@ -0,0 +1,87 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Selects proxies for HTTP requests. + * + *

Failover

+ *

ProxySelector implementations can return multiple {@link ProxyConfiguration} objects. + * Implementations will try to connect to each proxy, one after the other, until a connection can be established. + * To prevent proxy failover, return only a single result using {@link #noFailover(ProxySelector)}. + * + *

Implementations must be thread-safe. + */ +public interface ProxySelector { + /** + * Returns an ordered list of proxies to try for the given request. + * + *

An empty list means "connect directly". + * + * @param target the target URI of the request + * @return ordered list of proxies to try (may be empty, never null) + */ + List select(SmithyUri target); + + /** + * Notifies the selector that a connection via the given proxy failed. + * + *

Implementations can use this to update health / backoff state. + * + * @param target the original request target + * @param proxy the proxy that failed + * @param cause the IOException that occurred + */ + default void connectFailed(SmithyUri target, ProxyConfiguration proxy, IOException cause) { + // default no-op + } + + /** + * Returns a ProxySelector that always uses the given proxy configurations in order. + * + * @param config proxy configurations + * @return the created ProxySelector. + */ + static ProxySelector of(ProxyConfiguration... config) { + var result = List.of(config); + return target -> result; + } + + /** + * Returns a ProxySelector that never uses a proxy. + * + * @return the direct proxy. + */ + static ProxySelector direct() { + return target -> Collections.emptyList(); + } + + /** + * Returns a ProxySelector that takes the first result of the selector to prevent failover. + * + * @param delegate Delegate selector to wrap. + * @return the ProxySelector that does not use failover. + */ + static ProxySelector noFailover(ProxySelector delegate) { + return new ProxySelector() { + @Override + public List select(SmithyUri target) { + var proxies = delegate.select(target); + return proxies.isEmpty() ? proxies : List.of(proxies.getFirst()); + } + + @Override + public void connectFailed(SmithyUri target, ProxyConfiguration proxy, IOException cause) { + delegate.connectFailed(target, proxy, cause); + } + }; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/RequestOptions.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/RequestOptions.java new file mode 100644 index 0000000000..4fdefd6da1 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/RequestOptions.java @@ -0,0 +1,238 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import java.time.Duration; +import java.util.Objects; +import software.amazon.smithy.java.http.api.HeaderName; +import software.amazon.smithy.java.http.api.HttpRequest; + +/** + * Per-request configuration. Every option is nullable; a null value falls back to the corresponding + * client-level default (or, for {@link #expectContinue()}, to the request's {@code Expect} header). + */ +public final class RequestOptions { + + private static final String CONTINUE = "100-continue"; + private static final RequestOptions DEFAULTS = builder().build(); + + private final Duration requestTimeout; + private final Duration connectTimeout; + private final Duration readTimeout; + private final Duration acquireTimeout; + private final Boolean expectContinue; + + private RequestOptions(Builder b) { + this.requestTimeout = b.requestTimeout; + this.connectTimeout = b.connectTimeout; + this.readTimeout = b.readTimeout; + this.acquireTimeout = b.acquireTimeout; + this.expectContinue = b.expectContinue; + } + + /** + * @return default (all-null) request options. + */ + public static RequestOptions defaults() { + return DEFAULTS; + } + + /** + * @return a new builder for {@link RequestOptions}. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Overall per-request timeout (the whole send), or null for the client default. + */ + public Duration requestTimeout() { + return requestTimeout; + } + + /** + * TCP connect timeout for a new connection, or null for the client default. + */ + public Duration connectTimeout() { + return connectTimeout; + } + + /** + * Socket read / inactivity timeout, or null for the client default. + */ + public Duration readTimeout() { + return readTimeout; + } + + /** + * Max wait to obtain a connection from the pool, or null for the client default. + */ + public Duration acquireTimeout() { + return acquireTimeout; + } + + /** + * {@code Expect: 100-continue} handling: {@code TRUE} adds the header if absent, {@code FALSE} + * suppresses it even if the request carries it, {@code null} defers to the request's {@code Expect} + * header (the default behavior). + * + *

The full handshake (sending only the headers, then waiting for an interim {@code 100} response + * before writing the body) is performed on HTTP/1.1 only. On HTTP/2 this toggle controls only whether + * the header is on the wire; the request body is sent without waiting. + */ + public Boolean expectContinue() { + return expectContinue; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o == null || getClass() != o.getClass()) { + return false; + } + RequestOptions that = (RequestOptions) o; + return Objects.equals(requestTimeout, that.requestTimeout) + && Objects.equals(connectTimeout, that.connectTimeout) + && Objects.equals(readTimeout, that.readTimeout) + && Objects.equals(acquireTimeout, that.acquireTimeout) + && Objects.equals(expectContinue, that.expectContinue); + } + + @Override + public int hashCode() { + return Objects.hash(requestTimeout, connectTimeout, readTimeout, acquireTimeout, expectContinue); + } + + @Override + public String toString() { + return "RequestOptions{acquireTimeout=" + acquireTimeout + ", requestTimeout=" + requestTimeout + + ", connectTimeout=" + connectTimeout + ", readTimeout=" + readTimeout + + ", expectContinue=" + expectContinue + '}'; + } + + /** + * Returns {@code request} with its {@code Expect: 100-continue} header normalized to match + * {@link #expectContinue()}, so the on-the-wire headers and the client's continue-handshake decision + * stay consistent. {@code TRUE} adds the header if absent, {@code FALSE} strips it, {@code null} + * leaves the request untouched. + * + *

When a change is required it is applied via {@link HttpRequest#toModifiable()}: an already-modifiable + * request is mutated in place (and returned as the same instance), while an immutable one is copied and the copy + * mutated. + * + * @param request the request to normalize + * @return the request with its {@code Expect} header normalized + */ + public HttpRequest applyExpectContinue(HttpRequest request) { + if (expectContinue == null) { + return request; + } + + String header = request.headers().firstValue(HeaderName.EXPECT); + boolean present = header != null && header.equalsIgnoreCase(CONTINUE); + if (expectContinue) { + return present + ? request + : request.toModifiable().setHeader(HeaderName.EXPECT, CONTINUE); + } else if (!present) { + return request; + } else { + return request.toModifiable().removeHeader(HeaderName.EXPECT); + } + } + + /** + * Builder for {@link RequestOptions}. Every setter is optional; an unset (or null) value falls back to + * the client-level default for that option. + */ + public static final class Builder { + private Duration requestTimeout; + private Duration connectTimeout; + private Duration readTimeout; + private Duration acquireTimeout; + private Boolean expectContinue; + + private Builder() {} + + /** + * Sets the overall timeout for the entire send, or null to use the client default. + * + * @param requestTimeout the timeout; must be positive if non-null + * @return this builder + * @throws IllegalArgumentException if {@code requestTimeout} is zero or negative + */ + public Builder requestTimeout(Duration requestTimeout) { + this.requestTimeout = requirePositiveOrNull(requestTimeout, "requestTimeout"); + return this; + } + + /** + * Sets the TCP connect timeout for establishing a new connection, or null to use the client default. + * + * @param connectTimeout the timeout; must be positive if non-null + * @return this builder + * @throws IllegalArgumentException if {@code connectTimeout} is zero or negative + */ + public Builder connectTimeout(Duration connectTimeout) { + this.connectTimeout = requirePositiveOrNull(connectTimeout, "connectTimeout"); + return this; + } + + /** + * Sets the socket read / inactivity timeout, or null to use the client default. + * + * @param readTimeout the timeout; must be positive if non-null + * @return this builder + * @throws IllegalArgumentException if {@code readTimeout} is zero or negative + */ + public Builder readTimeout(Duration readTimeout) { + this.readTimeout = requirePositiveOrNull(readTimeout, "readTimeout"); + return this; + } + + /** + * Sets the maximum time to wait for a connection from the pool, or null to use the client default. + * + * @param acquireTimeout the timeout; must be positive if non-null + * @return this builder + * @throws IllegalArgumentException if {@code acquireTimeout} is zero or negative + */ + public Builder acquireTimeout(Duration acquireTimeout) { + this.acquireTimeout = requirePositiveOrNull(acquireTimeout, "acquireTimeout"); + return this; + } + + /** + * Controls {@code Expect: 100-continue} handling for this request: {@code TRUE} adds the header if + * absent, {@code FALSE} suppresses it even if the request carries the header, and {@code null} (the + * default) defers to the request's {@code Expect} header. The full wait-for-{@code 100} handshake is + * performed on HTTP/1.1 only; on HTTP/2 this toggles only the header. See {@link #expectContinue()}. + * + * @param expectContinue the toggle, or null to defer to the request header + * @return this builder + */ + public Builder expectContinue(Boolean expectContinue) { + this.expectContinue = expectContinue; + return this; + } + + /** + * @return a new {@link RequestOptions} with the values configured on this builder. + */ + public RequestOptions build() { + return new RequestOptions(this); + } + + private static Duration requirePositiveOrNull(Duration d, String name) { + if (d != null && (d.isNegative() || d.isZero())) { + throw new IllegalArgumentException(name + " must be positive or null: " + d); + } + return d; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/CloseReason.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/CloseReason.java new file mode 100644 index 0000000000..33e2ca1fa3 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/CloseReason.java @@ -0,0 +1,54 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +/** + * Reason why a connection was closed by the connection pool. + */ +public enum CloseReason { + /** + * Connection was idle too long. + * + *

Used when the pool's background cleanup removes idle connections. + */ + IDLE_TIMEOUT, + + /** + * Connection was closed unexpectedly. + * + *

The socket was closed by the peer, reset, or encountered an I/O error. + */ + UNEXPECTED_CLOSE, + + /** + * Connection couldn't be pooled because the pool was full. + * + *

The user returned the connection but the per-route pool was at capacity. + */ + POOL_FULL, + + /** + * Connection closed due to pool shutdown. + * + *

The pool is closing and all connections are being terminated. + */ + POOL_SHUTDOWN, + + /** + * User explicitly evicted the connection. + * + *

The user called {@link ConnectionPool#evict} with {@code isError=false}. + */ + EVICTED, + + /** + * User evicted the connection due to an error. + * + *

The user called {@link ConnectionPool#evict} with {@code isError=true}, + * indicating an error occurred during use. + */ + ERRORED +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionConfig.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionConfig.java new file mode 100644 index 0000000000..5c1dd9c45a --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionConfig.java @@ -0,0 +1,289 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.dns.DnsResolver; + +/** + * Immutable connection configuration used to create a {@link ConnectionPool}. + */ +public record ConnectionConfig( + int maxTotalConnections, + int maxConnectionsPerRoute, + int h2StreamsPerConnection, + int h2InitialWindowSize, + int h2MaxFrameSize, + int h2BufferSize, + Duration maxIdleTime, + Duration acquireTimeout, + Duration connectTimeout, + Duration tlsNegotiationTimeout, + Duration readTimeout, + Duration writeTimeout, + SSLContext sslContext, + SSLParameters sslParameters, + TlsProvider tlsProvider, + HttpVersionPolicy versionPolicy, + DnsResolver dnsResolver, + HttpSocketFactory socketFactory, + Integer socketReceiveBufferSize, + Integer socketSendBufferSize, + int tlsReadBufferSize, + int tlsWriteBufferSize, + List listeners) { + public ConnectionConfig { + if (maxTotalConnections <= 0) { + throw new IllegalArgumentException("maxTotalConnections must be positive: " + maxTotalConnections); + } + if (maxConnectionsPerRoute <= 0) { + throw new IllegalArgumentException("maxConnectionsPerRoute must be positive: " + maxConnectionsPerRoute); + } + if (maxTotalConnections < maxConnectionsPerRoute) { + throw new IllegalArgumentException( + "maxTotalConnections (" + maxTotalConnections + ") must be >= maxConnectionsPerRoute (" + + maxConnectionsPerRoute + ")"); + } + if (h2StreamsPerConnection <= 0) { + throw new IllegalArgumentException("h2StreamsPerConnection must be positive: " + h2StreamsPerConnection); + } + if (h2InitialWindowSize <= 0) { + throw new IllegalArgumentException("h2InitialWindowSize must be positive: " + h2InitialWindowSize); + } + if (h2MaxFrameSize < 16384 || h2MaxFrameSize > 16777215) { + throw new IllegalArgumentException("h2MaxFrameSize must be between 16384 and 16777215: " + h2MaxFrameSize); + } + if (h2BufferSize < 16 * 1024) { + throw new IllegalArgumentException("h2BufferSize must be at least 16KB: " + h2BufferSize); + } + requireNonNegative(maxIdleTime, "maxIdleTime"); + if (maxIdleTime.isZero()) { + throw new IllegalArgumentException("maxIdleTime must be positive: " + maxIdleTime); + } + requireNonNegative(acquireTimeout, "acquireTimeout"); + requireNonNegative(connectTimeout, "connectTimeout"); + requireNonNegative(tlsNegotiationTimeout, "tlsNegotiationTimeout"); + requireNonNegative(readTimeout, "readTimeout"); + requireNonNegative(writeTimeout, "writeTimeout"); + Objects.requireNonNull(versionPolicy, "versionPolicy"); + // socketFactory may be null, meaning "use the buffer-applying default" (see HttpConnectionPool). + if (socketReceiveBufferSize != null && (socketReceiveBufferSize < -1 || socketReceiveBufferSize == 0)) { + throw new IllegalArgumentException( + "socketReceiveBufferSize must be positive or -1: " + socketReceiveBufferSize); + } + if (socketSendBufferSize != null && (socketSendBufferSize < -1 || socketSendBufferSize == 0)) { + throw new IllegalArgumentException("socketSendBufferSize must be positive or -1: " + socketSendBufferSize); + } + if (tlsReadBufferSize <= 0) { + throw new IllegalArgumentException("tlsReadBufferSize must be positive: " + tlsReadBufferSize); + } + if (tlsWriteBufferSize <= 0) { + throw new IllegalArgumentException("tlsWriteBufferSize must be positive: " + tlsWriteBufferSize); + } + + listeners = List.copyOf(listeners); + if (sslContext == null) { + try { + sslContext = SSLContext.getDefault(); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Failed to get default SSLContext", e); + } + } + } + + public static Builder builder() { + return new Builder(); + } + + private static void requireNonNegative(Duration duration, String name) { + if (duration == null || duration.isNegative()) { + throw new IllegalArgumentException(name + " must be non-negative: " + duration); + } + } + + public static class Builder { + int maxTotalConnections = 256; + int maxConnectionsPerRoute = 256; + int h2StreamsPerConnection = 100; + int h2InitialWindowSize = 65535; + int h2MaxFrameSize = 16384; + int h2BufferSize = 256 * 1024; + + Duration maxIdleTime = Duration.ofMinutes(2); + Duration acquireTimeout = Duration.ofSeconds(30); + Duration connectTimeout = Duration.ofSeconds(10); + Duration tlsNegotiationTimeout = Duration.ofSeconds(10); + Duration readTimeout = Duration.ofSeconds(30); + Duration writeTimeout = Duration.ofSeconds(30); + SSLContext sslContext; + SSLParameters sslParameters; + TlsProvider tlsProvider; + HttpVersionPolicy versionPolicy = HttpVersionPolicy.AUTOMATIC; + DnsResolver dnsResolver; + HttpSocketFactory socketFactory; // null => HttpConnectionPool synthesizes the default + Integer socketReceiveBufferSize; + Integer socketSendBufferSize; + int tlsReadBufferSize = 16 * 1024; + int tlsWriteBufferSize = 16 * 1024; + final List listeners = new LinkedList<>(); + + protected Builder() {} + + public Builder maxConnectionsPerRoute(int max) { + this.maxConnectionsPerRoute = max; + return this; + } + + public Builder maxTotalConnections(int max) { + this.maxTotalConnections = max; + return this; + } + + public Builder maxIdleTime(Duration duration) { + this.maxIdleTime = duration; + return this; + } + + public Builder acquireTimeout(Duration timeout) { + this.acquireTimeout = timeout; + return this; + } + + public Builder connectTimeout(Duration timeout) { + this.connectTimeout = timeout; + return this; + } + + public Builder tlsNegotiationTimeout(Duration timeout) { + this.tlsNegotiationTimeout = timeout; + return this; + } + + public Builder readTimeout(Duration timeout) { + this.readTimeout = timeout; + return this; + } + + public Builder writeTimeout(Duration timeout) { + this.writeTimeout = timeout; + return this; + } + + public Builder sslContext(SSLContext context) { + this.sslContext = context; + return this; + } + + public Builder sslParameters(SSLParameters parameters) { + this.sslParameters = parameters; + return this; + } + + public Builder tlsProvider(TlsProvider provider) { + this.tlsProvider = provider; + return this; + } + + public Builder httpVersionPolicy(HttpVersionPolicy policy) { + this.versionPolicy = Objects.requireNonNull(policy, "httpVersionPolicy cannot be null"); + return this; + } + + public Builder dnsResolver(DnsResolver resolver) { + this.dnsResolver = Objects.requireNonNull(resolver, "dnsResolver must not be null"); + return this; + } + + public Builder socketFactory(HttpSocketFactory socketFactory) { + this.socketFactory = Objects.requireNonNull(socketFactory, "socketFactory"); + return this; + } + + public Builder socketReceiveBufferSize(int bytes) { + this.socketReceiveBufferSize = bytes; + return this; + } + + public Builder socketSendBufferSize(int bytes) { + this.socketSendBufferSize = bytes; + return this; + } + + public Builder tlsReadBufferSize(int bytes) { + this.tlsReadBufferSize = bytes; + return this; + } + + public Builder tlsWriteBufferSize(int bytes) { + this.tlsWriteBufferSize = bytes; + return this; + } + + public Builder h2InitialWindowSize(int windowSize) { + this.h2InitialWindowSize = windowSize; + return this; + } + + public Builder h2MaxFrameSize(int frameSize) { + this.h2MaxFrameSize = frameSize; + return this; + } + + public Builder h2StreamsPerConnection(int streams) { + this.h2StreamsPerConnection = streams; + return this; + } + + public Builder h2BufferSize(int bufferSize) { + this.h2BufferSize = bufferSize; + return this; + } + + public Builder addListener(HttpClientListener listener) { + listeners.add(Objects.requireNonNull(listener, "listener")); + return this; + } + + public Builder addListenerFirst(HttpClientListener listener) { + listeners.addFirst(Objects.requireNonNull(listener, "listener")); + return this; + } + + public ConnectionConfig build() { + return new ConnectionConfig( + maxTotalConnections, + maxConnectionsPerRoute, + h2StreamsPerConnection, + h2InitialWindowSize, + h2MaxFrameSize, + h2BufferSize, + maxIdleTime, + acquireTimeout, + connectTimeout, + tlsNegotiationTimeout, + readTimeout, + writeTimeout, + sslContext, + sslParameters, + tlsProvider, + versionPolicy, + dnsResolver, + socketFactory, + socketReceiveBufferSize, + socketSendBufferSize, + tlsReadBufferSize, + tlsWriteBufferSize, + listeners); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionPool.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionPool.java new file mode 100644 index 0000000000..f1f56002f6 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionPool.java @@ -0,0 +1,72 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.time.Duration; +import software.amazon.smithy.java.http.client.RequestOptions; + +/** + * Connection pool for managing HTTP connections. + * + *

Pools connections by {@link Route}, validates health before reuse, and enforces connection limits. + * All methods must be thread-safe. + * + * @see HttpConnectionPool + */ +public interface ConnectionPool extends AutoCloseable { + /** + * Acquire a connection for the given route. + * + *

Returns a pooled connection if available and healthy, otherwise creates new. + * Blocks until a connection is available or limits are exceeded. + * + * @param route the route to connect to + * @param exchangeId opaque client-generated exchange id used to correlate listener events + * @param options per-request options; non-null overrides (connect/read/acquire timeouts) take + * precedence over the pool's configured defaults + * @return a usable connection + * @throws IOException if connection cannot be established + * @throws IllegalStateException if pool is closed + */ + HttpConnection acquire(Route route, long exchangeId, RequestOptions options) throws IOException; + + /** + * Release a connection back to the pool for reuse. + * + *

Use for normal completion. Use {@link #evict} if connection is broken. + * + * @param connection the connection to release + */ + void release(HttpConnection connection); + + /** + * Evict a connection without returning it to the pool. + * + *

Use when the connection should not be reused. The connection is closed immediately. + * + * @param connection the connection to evict + * @param isError true if eviction is due to an error (IOException, protocol error, etc.), + * false for intentional eviction + */ + void evict(HttpConnection connection, boolean isError); + + /** + * Gracefully shut down, waiting for active connections to complete. + * + * @param gracePeriod maximum time to wait before force-closing + * @throws IOException if connections fail to close + */ + void shutdown(Duration gracePeriod) throws IOException; + + /** + * Close the pool and all connections. Idempotent. + * + * @throws IOException if connections fail to close + */ + @Override + void close() throws IOException; +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionTransport.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionTransport.java new file mode 100644 index 0000000000..110971ee23 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ConnectionTransport.java @@ -0,0 +1,142 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import javax.net.ssl.SSLSession; + +/** + * A transport connection providing I/O streams, channels, and TLS metadata. + * + *

Abstracts over plain sockets and SSLEngine-based TLS connections, + * allowing H1/H2 connections to work with either without knowing the + * underlying transport mechanism. + * + *

Provides both stream-based (InputStream/OutputStream) and channel-based + * (ReadableByteChannel/WritableByteChannel) I/O. The channel API lets callers use + * ByteBuffers directly and avoid some intermediate byte[] copies. + * + *

This is the transport SPI for alternate TLS providers: a {@link TlsProvider} returns a + * {@code ConnectionTransport} from {@link TlsProvider#connect}, and an implementation may live in a + * separate module (e.g. a native TLS stack that does its own I/O rather than driving a JDK + * {@code SSLEngine}). The H1/H2 layers consume only this interface and never observe which provider + * produced it. + */ +public interface ConnectionTransport extends AutoCloseable { + /** + * Create a transport backed by a plain {@link Socket} or {@link javax.net.ssl.SSLSocket}. + * + * @param socket connected socket + * @return socket-backed transport + */ + static ConnectionTransport of(Socket socket) { + return new SocketTransport(socket); + } + + /** + * Stream view of inbound (already-decrypted, for TLS transports) bytes. Reads honor the current + * {@link #setReadTimeout(int) read timeout}. + * + * @return an input stream over the connection's plaintext bytes + * @throws IOException if the stream cannot be obtained + */ + InputStream inputStream() throws IOException; + + /** + * Stream view for writing outbound bytes (encrypted before transmission, for TLS transports). + * + * @return an output stream over the connection + * @throws IOException if the stream cannot be obtained + */ + OutputStream outputStream() throws IOException; + + /** + * Get a readable channel for ByteBuffer reads. + * + *

For TLS transports, this unwraps data directly into the caller's + * ByteBuffer, avoiding intermediate byte[] copies. For plain socket + * transports, this wraps the socket's channel or input stream. + * + * @return a readable byte channel + */ + ReadableByteChannel readableChannel() throws IOException; + + /** + * Returns true if this transport already has plaintext bytes buffered below + * the channel returned by {@link #readableChannel()}. + * + *

This is a non-blocking hint used for read batching. Returning false is + * always safe; it only means callers may wake a consumer earlier than necessary. + * + * @return true if plaintext data is available without socket I/O. + */ + default boolean hasBufferedData() { + return false; + } + + /** + * Get a writable channel for ByteBuffer writes. + * + *

For TLS transports, this wraps data directly from the caller's + * ByteBuffer through SSLEngine, avoiding intermediate copies. + * + * @return a writable byte channel + */ + WritableByteChannel writableChannel() throws IOException; + + /** + * Per-connection TLS metadata. Used for observability (e.g. logging the negotiated cipher suite) + * and is not required for I/O. A provider that does not expose a JSSE session may return null; + * callers must tolerate null (including for plaintext connections). + * + * @return the SSL session for a TLS connection, or null if unavailable / not TLS + */ + SSLSession sslSession(); + + /** + * The application protocol selected by ALPN during the handshake. Drives HTTP/1.1-vs-HTTP/2 + * selection, so a TLS provider that negotiated ALPN must report it here. + * + * @return the negotiated protocol (e.g. {@code "h2"}, {@code "http/1.1"}), or null if none + */ + String negotiatedProtocol(); + + /** + * Whether the underlying connection is still usable. Pooled connections are validated with this + * before reuse. + * + * @return true if the connection is open + */ + boolean isOpen(); + + /** + * Set the read timeout applied to subsequent reads. + * + * @param timeoutMs timeout in milliseconds; 0 means no timeout (block indefinitely) + * @throws IOException if the timeout cannot be applied to the underlying transport + */ + void setReadTimeout(int timeoutMs) throws IOException; + + /** + * @return the current read timeout in milliseconds (0 means no timeout) + * @throws IOException if the timeout cannot be read from the underlying transport + */ + int getReadTimeout() throws IOException; + + /** + * Close the connection and release its resources. Implementations must be idempotent and must free + * any provider-native resources (e.g. a reference-counted native engine) exactly once. + * + * @throws IOException if closing the underlying transport fails + */ + @Override + void close() throws IOException; +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollChannel.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollChannel.java new file mode 100644 index 0000000000..39d38c37de --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollChannel.java @@ -0,0 +1,464 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.channel.epoll.EpollAccess; +import io.netty.channel.unix.Socket; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +/** + * A single TCP connection with a blocking virtual-thread API ({@link #readAddress}/ + * {@link #writeAddress}) backed by persistent epoll registration in an {@link EpollRuntime}. + * + *

This class is package-private and instantiated only when the experimental epoll transport + * backend is enabled and {@link EpollRuntime#isAvailable()} is true. + */ +final class EpollChannel { + + private final EpollRuntime runtime; + private final Socket socket; + private final int fd; + private final int baseFlags; // EPOLLIN | EPOLLET | EPOLLRDHUP + // Shared wheel-timer watchdog for read deadlines (the SAME one the NIO SSLEngineTransport path + // uses). On the hot read path we park UNTIMED and let a one-shot wheel timeout close the channel + // if the deadline passes, an O(1) bucket arm/cancel per read. This deliberately avoids + // LockSupport.parkNanos, which arms a JDK DelayScheduler timer entry per read (a measurable + // cross-thread signal/unpark tax that the NIO path does not pay). Null => untimed reads. + private final Timer readTimer; + + // Read-direction park state. + private volatile Thread reader; + private volatile boolean readReady; + // Set by the read watchdog immediately before it closes the channel, so a parked reader that wakes + // to a closed channel can distinguish a deadline expiry (SocketTimeoutException) from a normal EOF. + private volatile boolean readTimedOut; + // Write-direction park state. + private volatile Thread writer; + private volatile boolean writeReady; + + private final AtomicBoolean closed = new AtomicBoolean(); + private volatile boolean epollOutArmed; + + private EpollChannel(EpollRuntime runtime, Socket socket, Timer readTimer) { + this.runtime = runtime; + this.socket = socket; + this.readTimer = readTimer; + this.fd = socket.intValue(); + this.baseFlags = EpollAccess.EPOLLIN | EpollAccess.EPOLLET | EpollAccess.EPOLLRDHUP; + } + + // --------------------------------------------------------------------- + // Factory + // --------------------------------------------------------------------- + + /** + * Open a fresh non-blocking stream socket, apply socket options, register it persistently, and + * connect (parking until writable if the kernel returns EINPROGRESS). + * + * @param runtime the shared epoll runtime + * @param remote the resolved remote address to connect to + * @param connectTimeoutMs connect deadline in milliseconds; {@code 0} means wait indefinitely + * @param options socket options to apply before connecting + */ + static EpollChannel connect( + EpollRuntime runtime, + InetSocketAddress remote, + int connectTimeoutMs, + SocketOptions options, + Timer readTimer + ) throws IOException { + Socket socket = Socket.newSocketStream(); + boolean ok = false; + try { + options.applyTo(socket); + EpollChannel ch = new EpollChannel(runtime, socket, readTimer); + runtime.register(ch.fd, ch, ch.baseFlags); // register before connect so events map + ch.doConnect(remote, deadlineNanos(connectTimeoutMs)); + ok = true; + return ch; + } finally { + if (!ok) { + runtime.deregister(socket.intValue()); + try { + socket.close(); + } catch (IOException ignore) { + // best effort + } + } + } + } + + private void doConnect(SocketAddress remote, long deadline) throws IOException { + if (socket.connect(remote)) { + return; // connected immediately (common on loopback) + } + // EINPROGRESS: arm EPOLLOUT, park until writable, then finish. + armEpollOut(); + try { + if (!awaitWritable(deadline)) { + throw new SocketTimeoutException("Connect timed out"); + } + while (!socket.finishConnect()) { + // Spurious wakeup before completion, so loop until finished or error thrown. + if (!awaitWritable(deadline)) { + throw new SocketTimeoutException("Connect timed out"); + } + } + } finally { + disarmEpollOut(); + } + } + + // --------------------------------------------------------------------- + // Blocking VT-style raw-address I/O (the hot path) + // --------------------------------------------------------------------- + + /** + * Read into {@code [base+pos, base+limit)} of an off-heap region (the memory address of a direct + * buffer, obtained via {@code io.netty.channel.unix.Buffer#memoryAddress}). Blocks the calling virtual + * thread until at least one byte is read (returning the count), EOF/peer-close/local-close is observed + * (returning {@code -1}), or, if {@code timeoutMs > 0}, the deadline passes (throwing + * {@link SocketTimeoutException}). + * + *

Uses Netty's {@code recvAddress}, which goes straight to {@code recv(2)} on the raw pointer, + * skipping the {@code GetDirectBufferAddress} + {@code ByteBuffer} bounds/{@code instanceof} + * overhead the {@code ByteBuffer} overload pays per call. + * + * @param base direct-buffer base memory address + * @param pos start offset within the region + * @param limit end offset within the region + * @param timeoutMs read deadline in milliseconds; {@code 0} means wait indefinitely + * @return bytes read ({@code >0}), or {@code -1} on EOF/close + */ + int readAddress(long base, int pos, int limit, int timeoutMs) throws IOException { + Timeout watchdog = (timeoutMs > 0 && readTimer != null) + ? readTimer.newTimeout(t -> fireReadTimeout(), timeoutMs, TimeUnit.MILLISECONDS) + : null; + try { + for (;;) { + if (closed.get()) { + if (readTimedOut) { + throw new SocketTimeoutException("Read timed out after " + timeoutMs + "ms"); + } + return -1; + } + if (pos >= limit) { + return 0; + } + int n = socket.recvAddress(base, pos, limit); // >0 bytes, 0 EAGAIN, -1 EOF + if (n > 0) { + return n; + } + if (n < 0) { + return -1; // EOF + } + awaitReadable(watchdog == null ? deadlineNanos(timeoutMs) : 0L); + } + } finally { + if (watchdog != null) { + watchdog.cancel(); + } + } + } + + private void fireReadTimeout() { + readTimedOut = true; + close(); + } + + /** + * Write all of {@code [base+pos, base+limit)} from an off-heap region (untimed, matching the JDK + * blocking-channel write path). Parks on EPOLLOUT under back-pressure, arming it exactly once for + * the duration of this call. + * + * @param base direct-buffer base memory address + * @param pos start offset within the region + * @param limit end offset within the region + */ + void writeAddress(long base, int pos, int limit) throws IOException { + boolean armed = false; + try { + while (pos < limit) { + if (closed.get()) { + throw new IOException("channel closed"); + } + int n = socket.sendAddress(base, pos, limit); // >0 bytes, 0 EAGAIN + if (n > 0) { + pos += n; + continue; + } + if (!armed) { + armEpollOut(); + armed = true; + } + awaitWritable(0L); // untimed + } + } finally { + if (armed) { + disarmEpollOut(); + } + } + } + + /** + * Write all remaining bytes in the provided buffers using {@code writev(2)}. Parks on EPOLLOUT + * under back-pressure, matching the blocking semantics of {@link #writeAddress}. + * + * @return bytes written, equal to the original total remaining byte count unless an exception is + * thrown + */ + long writev(ByteBuffer[] buffers, int offset, int length) throws IOException { + int end = offset + length; + long remaining = remaining(buffers, offset, end); + long written = 0; + boolean armed = false; + try { + while (remaining > 0) { + if (closed.get()) { + throw new IOException("channel closed"); + } + int first = firstRemaining(buffers, offset, end); + long n = socket.writev(buffers, first, end - first, remaining); + if (n > 0) { + advance(buffers, first, end, n); + written += n; + remaining -= n; + continue; + } + if (!armed) { + armEpollOut(); + armed = true; + } + awaitWritable(0L); // untimed + } + return written; + } finally { + if (armed) { + disarmEpollOut(); + } + } + } + + private static int firstRemaining(ByteBuffer[] buffers, int offset, int end) { + for (int i = offset; i < end; i++) { + if (buffers[i].hasRemaining()) { + return i; + } + } + return end; + } + + private static void advance(ByteBuffer[] buffers, int offset, int end, long bytes) { + for (int i = offset; i < end && bytes > 0; i++) { + ByteBuffer buffer = buffers[i]; + int remaining = buffer.remaining(); + if (remaining == 0) { + continue; + } + int consumed = (int) Math.min(bytes, remaining); + buffer.position(buffer.position() + consumed); + bytes -= consumed; + } + } + + private static long remaining(ByteBuffer[] buffers, int offset, int end) { + long result = 0; + for (int i = offset; i < end; i++) { + result += buffers[i].remaining(); + } + return result; + } + + private boolean awaitReadable(long deadline) throws InterruptedIOException { + reader = Thread.currentThread(); // publish waiter (volatile store) + try { + while (!readReady && !closed.get()) { + checkInterrupted(); + if (deadline == 0L) { + LockSupport.park(this); // re-check after publishing => no lost wakeup + } else { + long remaining = deadline - System.nanoTime(); + if (remaining <= 0L) { + return false; // timed out + } + LockSupport.parkNanos(this, remaining); + if (!readReady && !closed.get() && System.nanoTime() >= deadline) { + return false; + } + } + } + } finally { + reader = null; + } + readReady = false; // consume the readiness edge + return true; + } + + /** + * Park until writable. Returns true on a writability edge (or close), false if the deadline + * passed. + * + * @param deadline {@link System#nanoTime()}-relative deadline, or {@code 0} for no deadline + */ + private boolean awaitWritable(long deadline) throws InterruptedIOException { + writer = Thread.currentThread(); + try { + while (!writeReady && !closed.get()) { + checkInterrupted(); + if (deadline == 0L) { + LockSupport.park(this); + } else { + long remaining = deadline - System.nanoTime(); + if (remaining <= 0L) { + return false; + } + LockSupport.parkNanos(this, remaining); + if (!writeReady && !closed.get() && System.nanoTime() >= deadline) { + return false; + } + } + } + } finally { + writer = null; + } + writeReady = false; + return true; + } + + private static void checkInterrupted() throws InterruptedIOException { + if (Thread.interrupted()) { + Thread.currentThread().interrupt(); + throw new InterruptedIOException("Interrupted while waiting for socket readiness"); + } + } + + // --------------------------------------------------------------------- + // Poller callback (runs on the EpollReactor poller thread) + // --------------------------------------------------------------------- + + /** Called by the reactor's poller when this fd has events. Sets ready flags then unparks. */ + void onReady(int ev) { + boolean errOrHup = (ev & (EpollAccess.EPOLLERR | EpollRuntime.EPOLLHUP)) != 0; + if (errOrHup) { + // Surface to both directions; the parked recv/send will return EOF/throw. + wakeRead(); + wakeWrite(); + return; + } + if ((ev & (EpollAccess.EPOLLIN | EpollAccess.EPOLLRDHUP)) != 0) { + wakeRead(); + } + if ((ev & EpollAccess.EPOLLOUT) != 0) { + wakeWrite(); + } + } + + private void wakeRead() { + readReady = true; // set flag (volatile store) BEFORE reading waiter + Thread t = reader; // (volatile load) + if (t != null) { + LockSupport.unpark(t); + } + } + + private void wakeWrite() { + writeReady = true; + Thread t = writer; + if (t != null) { + LockSupport.unpark(t); + } + } + + // --------------------------------------------------------------------- + // EPOLLOUT arm/disarm: the only epoll_ctl on the hot path, and only under write back-pressure + // --------------------------------------------------------------------- + + private void armEpollOut() throws IOException { + if (!epollOutArmed) { + runtime.ctlMod(fd, baseFlags | EpollAccess.EPOLLOUT); + epollOutArmed = true; + } + } + + private void disarmEpollOut() { + if (epollOutArmed) { + try { + runtime.ctlMod(fd, baseFlags); + } catch (IOException ignore) { + // channel may be closing; ignore. + } + epollOutArmed = false; + } + } + + // --------------------------------------------------------------------- + // Lifecycle / accessors + // --------------------------------------------------------------------- + + boolean isOpen() { + return !closed.get(); + } + + int fd() { + return fd; + } + + void close() { + if (!closed.compareAndSet(false, true)) { + return; + } + runtime.deregister(fd); + // Wake any parked waiters so they observe `closed` and unwind. + readReady = true; + writeReady = true; + Thread r = reader; + Thread w = writer; + if (r != null) { + LockSupport.unpark(r); + } + if (w != null) { + LockSupport.unpark(w); + } + try { + socket.close(); + } catch (IOException ignore) { + // best effort + } + } + + private static long deadlineNanos(int timeoutMs) { + return timeoutMs > 0 ? System.nanoTime() + (long) timeoutMs * 1_000_000L : 0L; + } + + /** + * Socket options applied to the native epoll socket before connecting. Because the epoll backend + * does not go through {@link HttpSocketFactory}, these mirror the options the JDK NIO path would + * otherwise receive so the two backends are compared on equal footing. {@code null} buffer sizes + * leave the kernel default (autotuned). + */ + record SocketOptions(Integer receiveBufferSize, Integer sendBufferSize, boolean keepAlive) { + void applyTo(Socket socket) throws IOException { + socket.setTcpNoDelay(true); + socket.setKeepAlive(keepAlive); + if (receiveBufferSize != null) { + socket.setReceiveBufferSize(receiveBufferSize); + } + if (sendBufferSize != null) { + socket.setSendBufferSize(sendBufferSize); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollConnector.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollConnector.java new file mode 100644 index 0000000000..98a070d6cf --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollConnector.java @@ -0,0 +1,79 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.util.Timer; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * Owns the experimental persistent-registration epoll socket backend for secure connections: the + * shared {@link EpollRuntime} and the socket options to apply to each new {@link EpollChannel}. + * + *

This is an alternative to the JDK NIO {@link java.nio.channels.SocketChannel} for the TLS + * ({@link SSLEngineTransport}) path. It is created by {@link HttpConnectionPool} whenever + * {@link EpollRuntime#isAvailable()} is true (Linux with the native epoll library). On any other host + * the pool leaves this null and every connection uses the standard NIO path. + * + *

Because epoll connections do not flow through {@link HttpSocketFactory}, the connector applies + * the same {@code SO_RCVBUF}/{@code SO_SNDBUF}/{@code SO_KEEPALIVE}/{@code TCP_NODELAY} options the + * NIO socket factory would, so an A/B benchmark compares only the socket backend, not socket tuning. + */ +final class EpollConnector { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(EpollConnector.class); + + private final EpollRuntime runtime; + private final EpollChannel.SocketOptions socketOptions; + // Shared wheel-timer watchdog for read deadlines, handed to each channel. The SAME timer the NIO + // SSLEngineTransport path uses, so both backends enforce read timeouts identically (O(1) wheel + // arm/cancel) without the per-read DelayScheduler tax of LockSupport.parkNanos. + private final Timer readTimer; + + private EpollConnector(EpollRuntime runtime, EpollChannel.SocketOptions socketOptions, Timer readTimer) { + this.runtime = runtime; + this.socketOptions = socketOptions; + this.readTimer = readTimer; + } + + /** + * Create a connector if the epoll backend is requested and available; otherwise return null so + * the caller falls back to the NIO socket path. + * + * @param receiveBufferSize SO_RCVBUF to apply, or null for kernel autotune + * @param sendBufferSize SO_SNDBUF to apply, or null for kernel autotune + * @param readTimer shared wheel-timer watchdog for read deadlines + * @return a connector, or null if epoll is disabled or unavailable + */ + static EpollConnector createIfAvailable(Integer receiveBufferSize, Integer sendBufferSize, Timer readTimer) { + if (!EpollRuntime.isAvailable()) { + LOGGER.warn("Epoll transport requested but native epoll is unavailable on this host; " + + "falling back to the JDK NIO socket transport", EpollRuntime.unavailabilityCause()); + return null; + } + var options = new EpollChannel.SocketOptions(receiveBufferSize, sendBufferSize, true); + return new EpollConnector(EpollRuntime.shared(), options, readTimer); + } + + /** + * Open and connect a new epoll-backed channel to {@code address:port}. + * + * @param address the resolved remote IP + * @param port the remote port + * @param connectTimeoutMs connect deadline in milliseconds (0 = wait indefinitely) + * @return a connected channel (TLS not yet started) + */ + EpollChannel connect(InetAddress address, int port, int connectTimeoutMs) throws IOException { + return EpollChannel.connect( + runtime, + new InetSocketAddress(address, port), + connectTimeoutMs, + socketOptions, + readTimer); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollReactor.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollReactor.java new file mode 100644 index 0000000000..4a5fa7b2e7 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollReactor.java @@ -0,0 +1,136 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.channel.epoll.EpollAccess; +import io.netty.channel.epoll.EpollEventArray; +import io.netty.channel.unix.FileDescriptor; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReferenceArray; +import software.amazon.smithy.java.logging.InternalLogger; + +final class EpollReactor implements AutoCloseable { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(EpollReactor.class); + + /** EPOLLHUP is a fixed Linux constant not exported by Netty's Native; peer hangup. */ + static final int EPOLLHUP = 0x010; + + private final FileDescriptor epollFd; + private final FileDescriptor eventFd; + private final int epfd; + private final int evfd; + private final EpollEventArray events; + private final AtomicReferenceArray channels; + private final Thread poller; + private volatile boolean running = true; + + EpollReactor(String name, int maxFds, int eventArrayLen) throws IOException { + this.epollFd = EpollAccess.newEpollCreate(); + this.eventFd = EpollAccess.newEventFd(); + this.epfd = epollFd.intValue(); + this.evfd = eventFd.intValue(); + this.events = EpollAccess.newEventArray(eventArrayLen); + this.channels = new AtomicReferenceArray<>(maxFds); + // Register the wakeup eventfd (level-triggered EPOLLIN) so shutdown can unblock the poller. + EpollAccess.epollCtlAdd(epfd, evfd, EpollAccess.EPOLLIN); + this.poller = new Thread(this::pollLoop, name + "-poller"); + this.poller.setDaemon(true); + } + + void start() { + poller.start(); + } + + int epfd() { + return epfd; + } + + /** + * Register a freshly-created fd's channel. The slot is published BEFORE {@code epoll_ctl ADD} so + * the poller can never see an event for an fd it cannot map. + */ + void register(int fd, EpollChannel ch, int flags) throws IOException { + if (fd >= channels.length()) { + throw new IOException("fd " + fd + " exceeds map capacity " + channels.length()); + } + channels.set(fd, ch); + EpollAccess.epollCtlAdd(epfd, fd, flags); + } + + /** Change interest flags for an already-registered fd (e.g. arm/disarm EPOLLOUT). */ + void ctlMod(int fd, int flags) throws IOException { + EpollAccess.epollCtlMod(epfd, fd, flags); + } + + /** Remove an fd from epoll and clear its slot. Safe to call once per fd before close(). */ + void deregister(int fd) { + try { + EpollAccess.epollCtlDel(epfd, fd); + } catch (IOException ignore) { + // fd may already be gone (e.g. closed); DEL on a closed fd is harmless here. + } + if (fd < channels.length()) { + channels.set(fd, null); + } + } + + private void pollLoop() { + try { + while (running) { + int n = EpollAccess.epollWait(epollFd, events, -1); // block until ready or wakeup + for (int i = 0; i < n; i++) { + int fd = EpollAccess.fd(events, i); + int ev = EpollAccess.events(events, i); + if (fd == evfd) { + EpollAccess.eventFdRead(evfd); // drain the wakeup + continue; + } + EpollChannel ch = channels.get(fd); + if (ch == null) { + continue; + } + try { + ch.onReady(ev); + } catch (Throwable t) { + LOGGER.error("epoll onReady failed for fd " + fd, t); + } + } + } + } catch (Throwable t) { + if (running) { + LOGGER.error("epoll poller died", t); + } + } + } + + /** Wake the poller (used to unblock epoll_wait during shutdown). */ + void wakeup() { + EpollAccess.eventFdWrite(evfd, 1L); + } + + @Override + public void close() { + running = false; + wakeup(); + try { + poller.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + try { + epollFd.close(); + } catch (IOException ignore) { + // best effort + } + try { + eventFd.close(); + } catch (IOException ignore) { + // best effort + } + EpollAccess.free(events); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollRuntime.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollRuntime.java new file mode 100644 index 0000000000..f73239d1e8 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollRuntime.java @@ -0,0 +1,135 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.channel.epoll.Epoll; +import java.io.IOException; +import java.io.UncheckedIOException; +import software.amazon.smithy.java.logging.InternalLogger; + +final class EpollRuntime implements AutoCloseable { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(EpollRuntime.class); + + /** EPOLLHUP is a fixed Linux constant not exported by Netty's Native; peer hangup. */ + static final int EPOLLHUP = EpollReactor.EPOLLHUP; + + private static final int MAX_FDS = 1 << 16; + private static final int EVENT_ARRAY_LEN = 256; + + private final EpollReactor[] reactors; + + private EpollRuntime(int shards, int maxFds, int eventArrayLen) throws IOException { + if (shards < 1) { + throw new IllegalArgumentException("shards must be >= 1"); + } + this.reactors = new EpollReactor[shards]; + for (int i = 0; i < shards; i++) { + reactors[i] = new EpollReactor("smithy-epoll-rt-" + i, maxFds, eventArrayLen); + } + } + + /** + * @return true if the native epoll transport is usable on this host (Linux with the native + * library loadable). When false, callers MUST use the JDK NIO socket path instead. + */ + static boolean isAvailable() { + return Epoll.isAvailable(); + } + + /** + * @return the cause of unavailability for diagnostics, or null if epoll is available. + */ + static Throwable unavailabilityCause() { + return Epoll.unavailabilityCause(); + } + + /** + * The lazily-started, process-global epoll runtime. Only call after confirming + * {@link #isAvailable()}. + */ + static EpollRuntime shared() { + return Holder.INSTANCE; + } + + // Initialization-on-demand holder: the runtime (and its native epoll fds + poller threads) is + // created only on first use, so merely loading this class on a non-Linux host costs nothing. + private static final class Holder { + static final EpollRuntime INSTANCE = create(); + + private static EpollRuntime create() { + int shards = shardCount(); + try { + EpollRuntime runtime = new EpollRuntime(shards, MAX_FDS, EVENT_ARRAY_LEN); + runtime.start(); + LOGGER.info("Started epoll transport runtime with {} poller thread(s)", shards); + return runtime; + } catch (IOException e) { + throw new UncheckedIOException("Failed to start epoll transport runtime", e); + } + } + } + + /** + * Size the runtime by the same {@code jdk.poller*} system properties that drive the JDK + * virtual-thread blocking model, so both models are configured by one knob. The JDK runs + * {@code jdk.readPollers} read-poller threads plus {@code jdk.writePollers} write-poller threads + * (each count must be a power of two). Our reactor handles both readiness directions in a single + * epfd per shard, so we use {@code readPollers + writePollers} shards, the same total number of + * epoll poller platform threads the JDK would start. + */ + private static int shardCount() { + int read = pollerProp("jdk.readPollers", 1); + int write = pollerProp("jdk.writePollers", 1); + return read + write; + } + + private static int pollerProp(String name, int defaultValue) { + String s = System.getProperty(name); + if (s == null) { + return defaultValue; + } + int v = Integer.parseInt(s.trim()); + // Match the JDK's own constraint so the same flag is valid for both models. + if (v != Integer.highestOneBit(v)) { + throw new IllegalArgumentException(name + " is set to a value that is not a power of 2: " + v); + } + return v; + } + + private void start() { + for (EpollReactor r : reactors) { + r.start(); + } + } + + int shards() { + return reactors.length; + } + + private EpollReactor reactorFor(int fd) { + return reactors[(fd & 0x7fffffff) % reactors.length]; + } + + void register(int fd, EpollChannel ch, int flags) throws IOException { + reactorFor(fd).register(fd, ch, flags); + } + + void ctlMod(int fd, int flags) throws IOException { + reactorFor(fd).ctlMod(fd, flags); + } + + void deregister(int fd) { + reactorFor(fd).deregister(fd); + } + + @Override + public void close() { + for (EpollReactor r : reactors) { + r.close(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollTransport.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollTransport.java new file mode 100644 index 0000000000..3c60740580 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/EpollTransport.java @@ -0,0 +1,205 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.channel.unix.Buffer; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import javax.net.ssl.SSLSession; + +final class EpollTransport implements ConnectionTransport { + + private static final int SCRATCH_SIZE = 16 * 1024; + + private final EpollChannel channel; + private final EpollReadableChannel readableChannel = new EpollReadableChannel(); + private final EpollWritableChannel writableChannel = new EpollWritableChannel(); + private final InputStream inputStream = Channels.newInputStream(readableChannel); + private final OutputStream outputStream = Channels.newOutputStream(writableChannel); + private volatile int readTimeoutMs; + + EpollTransport(EpollChannel channel, int readTimeoutMs) { + this.channel = channel; + this.readTimeoutMs = readTimeoutMs; + } + + @Override + public InputStream inputStream() { + return inputStream; + } + + @Override + public OutputStream outputStream() { + return outputStream; + } + + @Override + public ReadableByteChannel readableChannel() { + return readableChannel; + } + + @Override + public WritableByteChannel writableChannel() { + return writableChannel; + } + + @Override + public SSLSession sslSession() { + return null; + } + + @Override + public String negotiatedProtocol() { + return null; + } + + @Override + public boolean isOpen() { + return channel.isOpen(); + } + + @Override + public void setReadTimeout(int timeoutMs) { + readTimeoutMs = timeoutMs; + } + + @Override + public int getReadTimeout() { + return readTimeoutMs; + } + + @Override + public void close() { + channel.close(); + } + + private final class EpollReadableChannel implements ReadableByteChannel { + private ByteBuffer scratch; + + @Override + public int read(ByteBuffer dst) throws IOException { + if (!isOpen()) { + return -1; + } + if (!dst.hasRemaining()) { + return 0; + } + if (dst.isDirect()) { + int pos = dst.position(); + int n = channel.readAddress(Buffer.memoryAddress(dst), pos, dst.limit(), readTimeoutMs); + if (n > 0) { + dst.position(pos + n); + } + return n; + } + + int want = dst.remaining(); + ByteBuffer direct = scratchBuffer(want); + // Cap the read at the destination's remaining bytes so a partially-reused scratch buffer + // (sized from an earlier larger read) can't overflow dst. + int cap = Math.min(want, direct.capacity()); + int n = channel.readAddress(Buffer.memoryAddress(direct), 0, cap, readTimeoutMs); + if (n > 0) { + direct.limit(n); + dst.put(direct); + } + return n; + } + + @Override + public boolean isOpen() { + return EpollTransport.this.isOpen(); + } + + @Override + public void close() { + EpollTransport.this.close(); + } + + private ByteBuffer scratchBuffer(int remaining) { + int size = Math.min(remaining, SCRATCH_SIZE); + ByteBuffer result = scratch; + if (result == null || result.capacity() < size) { + result = ByteBuffer.allocateDirect(size); + scratch = result; + } + result.clear(); + return result; + } + } + + private final class EpollWritableChannel implements GatheringByteChannel { + private ByteBuffer scratch; + + @Override + public int write(ByteBuffer src) throws IOException { + if (!isOpen()) { + throw new IOException("channel closed"); + } + if (!src.hasRemaining()) { + return 0; + } + + int len = src.remaining(); + if (src.isDirect()) { + int pos = src.position(); + channel.writeAddress(Buffer.memoryAddress(src), pos, src.limit()); + src.position(src.limit()); + return len; + } + + ByteBuffer direct = scratchBuffer(len); + int n = Math.min(len, direct.capacity()); + int limit = src.limit(); + src.limit(src.position() + n); + direct.put(src); + src.limit(limit); + direct.flip(); + channel.writeAddress(Buffer.memoryAddress(direct), 0, n); + return n; + } + + @Override + public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { + if (!isOpen()) { + throw new IOException("channel closed"); + } + return channel.writev(srcs, offset, length); + } + + @Override + public long write(ByteBuffer[] srcs) throws IOException { + return write(srcs, 0, srcs.length); + } + + @Override + public boolean isOpen() { + return EpollTransport.this.isOpen(); + } + + @Override + public void close() { + EpollTransport.this.close(); + } + + private ByteBuffer scratchBuffer(int remaining) { + int size = Math.min(remaining, SCRATCH_SIZE); + ByteBuffer result = scratch; + if (result == null || result.capacity() < size) { + result = ByteBuffer.allocateDirect(size); + scratch = result; + } + result.clear(); + return result; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManager.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManager.java new file mode 100644 index 0000000000..9117f2ecfe --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManager.java @@ -0,0 +1,426 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * Manages HTTP/1.1 connection pooling. + * + *

Pools idle connections per route using LIFO queues. Connections are + * validated before reuse and cleaned up when idle too long. + */ +final class H1ConnectionManager { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(H1ConnectionManager.class); + + // Skip expensive socket validation for connections idle < 1 second + private static final long VALIDATION_THRESHOLD_NANOS = 1_000_000_000L; + + private final ConcurrentHashMap pools = new ConcurrentHashMap<>(); + private final long maxIdleTimeNanos; + private volatile Route cachedRoute; + private volatile HostPool cachedPool; + + H1ConnectionManager(long maxIdleTimeNanos) { + this.maxIdleTimeNanos = maxIdleTimeNanos; + } + + /** + * Try to acquire a pooled connection for the route. + * + * @param route the route + * @param maxConnections max pooled connections for this route (used if pool doesn't exist) + * @return a valid pooled connection, or null if none available + */ + HttpConnection tryAcquire(Route route, int maxConnections) { + return tryAcquire(route, maxConnections, (connection, reason) -> {}); + } + + HttpConnection tryAcquire( + Route route, + int maxConnections, + BiConsumer onInvalidClose + ) { + HostPool hostPool = getOrCreatePool(route, maxConnections); + return hostPool.tryAcquireValid(route, maxIdleTimeNanos, onInvalidClose); + } + + /** + * Get or create a pool for the route. + * + * @param route the route + * @param maxConnections max pooled connections for this route + * @return the pool for the route + * @throws IllegalStateException if a pool exists with a different maxConnections + */ + HostPool getOrCreatePool(Route route, int maxConnections) { + Route currentRoute = cachedRoute; + HostPool currentPool = cachedPool; + if (route.equals(currentRoute) && currentPool != null) { + validatePoolConfig(route, currentPool, maxConnections); + return currentPool; + } + + return pools.compute(route, (k, existing) -> { + if (existing == null) { + existing = new HostPool(maxConnections); + } else { + validatePoolConfig(route, existing, maxConnections); + } + cachedRoute = route; + cachedPool = existing; + return existing; + }); + } + + void acquireActive(Route route, int maxConnections, long acquireTimeoutMs) throws IOException { + HostPool hostPool = getOrCreatePool(route, maxConnections); + try { + if (!hostPool.tryAcquireActive(acquireTimeoutMs)) { + throw new IOException("Connection pool exhausted for route " + route + + ": " + maxConnections + " connections in use (timed out after " + + acquireTimeoutMs + "ms)"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while waiting for active connection permit", e); + } + } + + void releaseActive(Route route) { + HostPool hostPool = getCachedPool(route); + if (hostPool == null) { + hostPool = pools.get(route); + } + if (hostPool != null) { + hostPool.releaseActive(); + } + } + + private static void validatePoolConfig(Route route, HostPool pool, int maxConnections) { + if (pool.maxConnections != maxConnections) { + throw new IllegalStateException( + "Pool for " + route + " already exists with maxConnections=" + pool.maxConnections + + ", cannot change to " + maxConnections); + } + } + + /** + * Release a connection back to the pool. + * + * @return true if pooled, false if pool full or closed + */ + boolean release(Route route, HttpConnection connection, boolean poolClosed) { + HostPool hostPool = getCachedPool(route); + if (hostPool == null) { + hostPool = pools.get(route); + } + if (hostPool == null) { + return false; + } + + boolean pooled = hostPool.release(connection, poolClosed); + if (pooled) { + LOGGER.debug("Released h1 connection to pool for {}", route); + } else { + LOGGER.debug("h1 pool full, not pooling connection to {}", route); + } + return pooled; + } + + /** + * Remove a specific connection from the pool. + */ + void remove(Route route, HttpConnection connection) { + HostPool hostPool = pools.get(route); + if (hostPool != null) { + hostPool.remove(connection); + } + } + + private HostPool getCachedPool(Route route) { + Route currentRoute = cachedRoute; + HostPool currentPool = cachedPool; + return route.equals(currentRoute) ? currentPool : null; + } + + /** + * Clean up idle and unhealthy connections, and remove empty pools. + * + * @param onRemove callback for each removed connection + * @return total number of connections removed + */ + int cleanupIdle(BiConsumer onRemove) { + int totalRemoved = 0; + for (HostPool pool : pools.values()) { + totalRemoved += pool.removeIdleConnections(maxIdleTimeNanos, onRemove); + } + + // Remove unused pools to prevent unbounded growth with dynamic routes. + // A pool with no idle connections can still have leased connections; dropping it would reset + // route permits and allow maxConnectionsPerRoute to be exceeded. + pools.entrySet().removeIf(e -> e.getValue().isUnused()); + clearStaleCache(); + return totalRemoved; + } + + /** + * Close all pooled connections. + */ + void closeAll(List exceptions, Consumer onClose) { + for (HostPool pool : pools.values()) { + pool.closeAll(exceptions, onClose); + } + pools.clear(); + cachedRoute = null; + cachedPool = null; + } + + private void clearStaleCache() { + Route currentRoute = cachedRoute; + HostPool currentPool = cachedPool; + if (currentRoute != null && currentPool != null && pools.get(currentRoute) != currentPool) { + cachedRoute = null; + cachedPool = null; + } + } + + private static CloseReason invalidReason(HttpConnection connection, long idleSinceNanos, long maxIdleTimeNanos) { + long idleNanos = System.nanoTime() - idleSinceNanos; + if (idleNanos >= maxIdleTimeNanos) { + return CloseReason.IDLE_TIMEOUT; + } + + if (!connection.isActive()) { + return CloseReason.UNEXPECTED_CLOSE; + } + + if (idleNanos > VALIDATION_THRESHOLD_NANOS) { + return connection.validateForReuse() ? null : CloseReason.UNEXPECTED_CLOSE; + } + + return null; + } + + /** + * Per-route connection pool using a lock-protected LIFO stack. + */ + private static final class HostPool { + private static final int INITIAL_IDLE_CAPACITY = 8; + + private HttpConnection[] available; + private long[] idleSinceNanos; + private final ReentrantLock lock = new ReentrantLock(); + private final Condition activeReleased = lock.newCondition(); + private final int maxConnections; + private int availableCount; + private int activeLeases; + + HostPool(int maxConnections) { + this.maxConnections = maxConnections; + int initialCapacity = Math.min(INITIAL_IDLE_CAPACITY, maxConnections); + this.available = new HttpConnection[initialCapacity]; + this.idleSinceNanos = new long[initialCapacity]; + } + + boolean tryAcquireActive(long acquireTimeoutMs) throws InterruptedException { + long nanos = TimeUnit.MILLISECONDS.toNanos(acquireTimeoutMs); + lock.lockInterruptibly(); + try { + while (activeLeases >= maxConnections) { + if (nanos <= 0) { + return false; + } + nanos = activeReleased.awaitNanos(nanos); + } + activeLeases++; + return true; + } finally { + lock.unlock(); + } + } + + void releaseActive() { + lock.lock(); + try { + releaseActiveLocked(); + } finally { + lock.unlock(); + } + } + + private void releaseActiveLocked() { + if (activeLeases > 0) { + activeLeases--; + activeReleased.signal(); + } + } + + boolean isUnused() { + lock.lock(); + try { + return availableCount == 0 && activeLeases == 0; + } finally { + lock.unlock(); + } + } + + HttpConnection tryAcquireValid( + Route route, + long maxIdleTimeNanos, + BiConsumer onInvalidClose + ) { + for (;;) { + HttpConnection connection; + long idleSince; + lock.lock(); + try { + if (availableCount == 0) { + return null; + } + int index = --availableCount; + connection = available[index]; + idleSince = idleSinceNanos[index]; + available[index] = null; + idleSinceNanos[index] = 0; + } finally { + lock.unlock(); + } + + CloseReason invalidReason = invalidReason(connection, idleSince, maxIdleTimeNanos); + if (invalidReason == null) { + LOGGER.debug("Reusing pooled connection to {}", route); + return connection; + } + + // Connection failed validation - close it and try next + LOGGER.debug("Closing invalid pooled connection to {}", route); + try { + connection.close(); + } catch (IOException e) { + LOGGER.debug("Error closing invalid connection to {}: {}", route, e.getMessage()); + } + onInvalidClose.accept(connection, invalidReason); + } + } + + boolean release(HttpConnection connection, boolean poolClosed) { + lock.lock(); + try { + releaseActiveLocked(); + if (!connection.isActive() || poolClosed || availableCount >= maxConnections) { + return false; + } + ensureIdleCapacity(); + available[availableCount] = connection; + idleSinceNanos[availableCount] = System.nanoTime(); + availableCount++; + return true; + } finally { + lock.unlock(); + } + } + + private void ensureIdleCapacity() { + if (availableCount < available.length) { + return; + } + + int nextCapacity; + if (available.length == 0) { + nextCapacity = 1; + } else { + nextCapacity = Math.min(maxConnections, available.length * 2); + } + available = Arrays.copyOf(available, nextCapacity); + idleSinceNanos = Arrays.copyOf(idleSinceNanos, nextCapacity); + } + + void remove(HttpConnection connection) { + lock.lock(); + try { + for (int i = 0; i < availableCount; i++) { + if (available[i] == connection) { + removeAt(i); + return; + } + } + } finally { + lock.unlock(); + } + } + + private void removeAt(int index) { + int last = --availableCount; + available[index] = available[last]; + idleSinceNanos[index] = idleSinceNanos[last]; + available[last] = null; + idleSinceNanos[last] = 0; + } + + int removeIdleConnections(long maxIdleNanos, BiConsumer onRemove) { + int removed = 0; + long now = System.nanoTime(); + lock.lock(); + try { + for (int i = 0; i < availableCount;) { + HttpConnection connection = available[i]; + long idleNanos = now - idleSinceNanos[i]; + boolean unhealthy = !connection.isActive(); + boolean expired = idleNanos > maxIdleNanos; + if (unhealthy || expired) { + CloseReason reason = expired && !unhealthy + ? CloseReason.IDLE_TIMEOUT + : CloseReason.UNEXPECTED_CLOSE; + try { + connection.close(); + } catch (IOException ignored) { + // ignored + } + onRemove.accept(connection, reason); + removeAt(i); + removed++; + } else { + i++; + } + } + } finally { + lock.unlock(); + } + return removed; + } + + void closeAll(List exceptions, Consumer onClose) { + lock.lock(); + try { + while (availableCount > 0) { + int index = --availableCount; + HttpConnection connection = available[index]; + available[index] = null; + idleSinceNanos[index] = 0; + try { + connection.close(); + } catch (IOException e) { + exceptions.add(e); + } + onClose.accept(connection); + } + } finally { + lock.unlock(); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2ConnectionManager.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2ConnectionManager.java new file mode 100644 index 0000000000..1987d3dbd0 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2ConnectionManager.java @@ -0,0 +1,394 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * Manages HTTP/2 connections with watermark load balancing. + * + *

Load Balancing Strategy

+ *

Uses a high-watermark strategy to distribute streams across connections. + * + *

Threading

+ *

Uses per-route state with a volatile connection array. Acquisition, connection creation, + * and removal coordinate through the per-route lock. + */ +final class H2ConnectionManager { + + private static final InternalLogger LOGGER = InternalLogger.getLogger(H2ConnectionManager.class); + + /** + * Per-route connection state. + */ + private static final class RouteState { + /** Connections for this route. Volatile for safe publication. */ + volatile MultiplexedHttpConnection[] conns = new MultiplexedHttpConnection[0]; + + /** Connections currently being created (prevents over-creation). Guarded by lock. */ + int pendingCreations = 0; + + /** Scratch buffer for active stream counts, guarded by lock. */ + int[] activeStreamsBuf = new int[4]; + + /** Lock for state modifications. ReentrantLock avoids VT pinning unlike synchronized. */ + final ReentrantLock lock = new ReentrantLock(); + final Condition available = lock.newCondition(); + } + + private static final MultiplexedHttpConnection[] EMPTY = new MultiplexedHttpConnection[0]; + + // Prefer opening idle H2 connections before placing a second active stream on an existing connection. + // Once maxConnectionsPerRoute is reached, streams are multiplexed up to the configured hard limit. + private static final int DEFAULT_SOFT_LIMIT = 1; + + private final ConcurrentHashMap routes = new ConcurrentHashMap<>(); + private final H2LoadBalancer loadBalancer; + private final long acquireTimeoutMs; + private final List listeners; + private final ConnectionFactory connectionFactory; + + @FunctionalInterface + interface ConnectionFactory { + MultiplexedHttpConnection create(Route route, long exchangeId, RequestOptions options) throws IOException; + } + + H2ConnectionManager( + int streamsPerConnection, + long acquireTimeoutMs, + List listeners, + ConnectionFactory connectionFactory + ) { + this.acquireTimeoutMs = acquireTimeoutMs; + this.listeners = listeners; + this.connectionFactory = connectionFactory; + this.loadBalancer = H2LoadBalancer.watermark(DEFAULT_SOFT_LIMIT, streamsPerConnection); + } + + private RouteState stateFor(Route route) { + return routes.computeIfAbsent(route, r -> new RouteState()); + } + + /** + * Acquire an HTTP/2 connection for the route, creating one if needed. + * + *

Connection creation happens outside the synchronized block to prevent deadlock + * when connection establishment blocks on I/O. + * + *

Note: Under high contention, we may create slightly more connections than strictly + * necessary. This is intentional - we bias toward expansion to avoid coordination + * bottlenecks, accepting minor over-provisioning as a tradeoff. + * + * @param route the target route + * @param maxConnectionsForRoute maximum connections allowed for this route + * @return an H2 connection ready for use + * @throws IOException if acquisition times out or is interrupted + */ + MultiplexedHttpConnection acquire(Route route, int maxConnectionsForRoute, long exchangeId, RequestOptions options) + throws IOException { + RouteState state = stateFor(route); + long acquireMs = options.acquireTimeout() != null ? options.acquireTimeout().toMillis() : acquireTimeoutMs; + long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(acquireMs); + + state.lock.lock(); + try { + while (true) { + MultiplexedHttpConnection[] snapshot = state.conns; + int connCount = snapshot.length; + int totalConns = connCount + state.pendingCreations; + + // Build active stream counts for the load balancer + if (state.activeStreamsBuf.length < connCount) { + state.activeStreamsBuf = new int[connCount]; + } + for (int i = 0; i < connCount; i++) { + state.activeStreamsBuf[i] = snapshot[i].getActiveStreamCountIfAccepting(); + } + + boolean canExpand = totalConns < maxConnectionsForRoute; + int selected = loadBalancer.select(state.activeStreamsBuf, + connCount, + canExpand ? maxConnectionsForRoute : connCount); + + if (selected >= 0) { + notifyAcquire(snapshot[selected], true); + return snapshot[selected]; + } else if (selected == H2LoadBalancer.CREATE_NEW && canExpand) { + if (state.pendingCreations > 0) { + // Another thread is already creating a connection, wait for it + // instead of creating a redundant one. + long remainingNanos = deadlineNanos - System.nanoTime(); + if (remainingNanos <= 0) { + throw new IOException("Acquire timeout: no connection available after " + + acquireTimeoutMs + "ms for " + route); + } + try { + state.available.awaitNanos(remainingNanos); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while waiting for connection", e); + } + continue; + } + state.pendingCreations++; + break; + } + + // Saturated: wait for capacity + LOGGER.debug("All {} connections saturated for route {}, waiting for capacity " + + "(canExpand={}, selected={})", connCount, route, canExpand, selected); + long remainingNanos = deadlineNanos - System.nanoTime(); + if (remainingNanos <= 0) { + throw new IOException("Acquire timeout: no connection available after " + + acquireTimeoutMs + "ms for " + route); + } + + try { + state.available.awaitNanos(remainingNanos); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while waiting for connection", e); + } + } + } finally { + state.lock.unlock(); + } + + return createNewH2Connection(route, state, exchangeId, options); + } + + private MultiplexedHttpConnection createNewH2Connection( + Route route, + RouteState state, + long exchangeId, + RequestOptions options + ) throws IOException { + // Create new connection OUTSIDE the lock to avoid deadlock. + MultiplexedHttpConnection newConn = null; + IOException createException = null; + try { + newConn = connectionFactory.create(route, exchangeId, options); + // Signal waiters when a stream is released so they can re-check capacity + newConn.setStreamReleaseCallback(() -> { + state.lock.lock(); + try { + state.available.signalAll(); + } finally { + state.lock.unlock(); + } + }); + } catch (IOException e) { + createException = e; + } finally { + // Register under lock (or decrement pending on failure) + state.lock.lock(); + try { + state.pendingCreations--; + if (newConn != null) { + MultiplexedHttpConnection[] cur = state.conns; + MultiplexedHttpConnection[] next = new MultiplexedHttpConnection[cur.length + 1]; + System.arraycopy(cur, 0, next, 0, cur.length); + next[cur.length] = newConn; + state.conns = next; + } + state.available.signalAll(); // Wake waiters + } finally { + state.lock.unlock(); + } + } + + if (createException != null) { + throw createException; + } + + notifyAcquire(newConn, false); + return newConn; + } + + /** + * Unregister a connection from the route. + */ + void unregister(Route route, MultiplexedHttpConnection conn) { + RouteState state = routes.get(route); + if (state == null) { + return; + } + state.lock.lock(); + try { + MultiplexedHttpConnection[] cur = state.conns; + int n = cur.length; + int idx = -1; + for (int i = 0; i < n; i++) { + if (cur[i] == conn) { + idx = i; + break; + } + } + + if (idx < 0) { + return; + } else if (n == 1) { + state.conns = EMPTY; + } else { + MultiplexedHttpConnection[] next = new MultiplexedHttpConnection[n - 1]; + System.arraycopy(cur, 0, next, 0, idx); + System.arraycopy(cur, idx + 1, next, idx, n - idx - 1); + state.conns = next; + } + state.available.signalAll(); + } finally { + state.lock.unlock(); + } + } + + void cleanupDead(Route route, BiConsumer onRemove) { + RouteState state = routes.get(route); + if (state == null) { + return; + } + + MultiplexedHttpConnection[] cur = state.conns; + + // Quick check without lock - if all look healthy, skip + boolean anyDead = false; + for (MultiplexedHttpConnection conn : cur) { + if (conn != null && (!conn.canAcceptMoreStreams() || !conn.isActive())) { + anyDead = true; + break; + } + } + if (!anyDead) { + return; + } + + // Slow path: actually clean up under lock + state.lock.lock(); + try { + cur = state.conns; // Re-read under lock + int n = cur.length; + MultiplexedHttpConnection[] tmp = new MultiplexedHttpConnection[n]; + int w = 0; + for (MultiplexedHttpConnection conn : cur) { + if (conn == null) { + continue; + } + if (!conn.canAcceptMoreStreams() || !conn.isActive()) { + CloseReason reason = conn.isActive() + ? CloseReason.EVICTED + : CloseReason.UNEXPECTED_CLOSE; + onRemove.accept(conn, reason); + } else { + tmp[w++] = conn; + } + } + if (w != n) { + MultiplexedHttpConnection[] next = new MultiplexedHttpConnection[w]; + System.arraycopy(tmp, 0, next, 0, w); + state.conns = next; + // Wake waiters - removed connections free capacity + state.available.signalAll(); + } + } finally { + state.lock.unlock(); + } + } + + void cleanupAllDead(BiConsumer onRemove) { + for (Route route : routes.keySet()) { + cleanupDead(route, onRemove); + } + } + + /** + * Clean up idle connections that have no active streams and have been idle longer than the specified timeout. + * + * @param maxIdleTimeNanos maximum idle time in nanoseconds + * @param onRemove callback for removed connections + */ + void cleanupIdle(long maxIdleTimeNanos, BiConsumer onRemove) { + for (RouteState state : routes.values()) { + MultiplexedHttpConnection[] cur = state.conns; + + // Quick check without lock - if none look idle, skip + boolean anyIdle = false; + for (MultiplexedHttpConnection conn : cur) { + if (conn != null && conn.getIdleTimeNanos() > maxIdleTimeNanos) { + anyIdle = true; + break; + } + } + if (!anyIdle) { + continue; + } + + // Slow path: clean up under lock + state.lock.lock(); + try { + cur = state.conns; // Re-read under lock + int n = cur.length; + MultiplexedHttpConnection[] tmp = new MultiplexedHttpConnection[n]; + int w = 0; + for (MultiplexedHttpConnection conn : cur) { + if (conn == null) { + continue; + } + if (conn.getIdleTimeNanos() > maxIdleTimeNanos) { + onRemove.accept(conn, CloseReason.IDLE_TIMEOUT); + } else { + tmp[w++] = conn; + } + } + if (w != n) { + MultiplexedHttpConnection[] next = new MultiplexedHttpConnection[w]; + System.arraycopy(tmp, 0, next, 0, w); + state.conns = next; + // Wake waiters - removed connections free capacity + state.available.signalAll(); + } + } finally { + state.lock.unlock(); + } + } + } + + /** + * Close all connections for shutdown. + * + *

This is a best-effort shutdown. In-flight acquires that already have a cached + * RouteState may continue to operate briefly. For hard shutdown semantics, callers + * should ensure no new requests are submitted before calling this method. + */ + void closeAll(BiConsumer onClose) { + for (RouteState state : routes.values()) { + MultiplexedHttpConnection[] snapshot = state.conns; + for (MultiplexedHttpConnection conn : snapshot) { + if (conn != null) { + onClose.accept(conn, CloseReason.POOL_SHUTDOWN); + } + } + } + routes.clear(); + } + + private void notifyAcquire(MultiplexedHttpConnection conn, boolean reused) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectionAcquired(conn, reused); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectionAcquired", e); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancer.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancer.java new file mode 100644 index 0000000000..98947d91a0 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancer.java @@ -0,0 +1,99 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Strategy for selecting the HTTP/2 connection to use or whether to create a new one. + * + *

The strategy receives an array of active stream counts (one per connection) and returns the index of the + * connection to use, or -1 to signal that a new connection should be created. + */ +@FunctionalInterface +interface H2LoadBalancer { + + /** Return value indicating a new connection should be created. */ + int CREATE_NEW = -1; + + /** Return value indicating all connections are saturated. */ + int SATURATED = -2; + + /** + * Select a connection index or signal new connection creation. + * + *

When {@code maxConnections == connectionCount}, the balancer must not return {@link #CREATE_NEW} + * (no room to expand). Return a valid index or {@link #SATURATED} instead. + * + * @param activeStreams active stream count per connection; a value of -1 means + * the connection is not accepting new streams + * @param connectionCount number of valid entries in activeStreams + * @param maxConnections maximum connections allowed; equals connectionCount when expansion is not possible + * @return index into activeStreams to use, {@link #CREATE_NEW}, or {@link #SATURATED} + */ + int select(int[] activeStreams, int connectionCount, int maxConnections); + + /** + * Create the default watermark-based HTTP/2 load balancer. + * + *

Green zone (under soft limit): round-robin. + * Expansion: all above soft limit and under max connections → {@link #CREATE_NEW}. + * Red zone (at max connections): least-loaded under hard limit. + * Saturated: returns {@link #SATURATED}. + * + * @param softLimit stream count where the balancer starts preferring expansion + * @param hardLimit maximum stream count accepted on an existing connection + * @return the load balancer + */ + static H2LoadBalancer watermark(int softLimit, int hardLimit) { + if (softLimit > hardLimit) { + throw new IllegalArgumentException("Soft limit must not exceed hard limit"); + } + + return new H2LoadBalancer() { + private final AtomicInteger nextIndex = new AtomicInteger(); + + @Override + public int select(int[] activeStreams, int connectionCount, int maxConnections) { + // Green zone: round-robin among connections under soft limit. + if (connectionCount > 0) { + int start = (nextIndex.getAndIncrement() & Integer.MAX_VALUE) % connectionCount; + for (int i = 0; i < connectionCount; i++) { + int idx = start + i; + if (idx >= connectionCount) { + idx -= connectionCount; + } + int active = activeStreams[idx]; + if (active >= 0 && active < softLimit) { + return idx; + } + } + } + + // Expansion: all above soft limit, create new if allowed. + if (connectionCount < maxConnections) { + return CREATE_NEW; + } + + // Red zone: least-loaded under hard limit. + int bestIdx = SATURATED; + int bestActive = Integer.MAX_VALUE; + for (int i = 0; i < connectionCount; i++) { + int active = activeStreams[i]; + if (active >= 0 && active < hardLimit && active < bestActive) { + bestIdx = i; + bestActive = active; + if (active == 0) { + break; + } + } + } + + return bestIdx; + } + }; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnection.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnection.java new file mode 100644 index 0000000000..b0c501bc20 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnection.java @@ -0,0 +1,92 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import javax.net.ssl.SSLSession; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.http.client.RequestOptions; + +/** + * Protocol-agnostic HTTP connection. + */ +public interface HttpConnection extends AutoCloseable { + /** + * Create a new HTTP exchange on this connection. + * + *

For HTTP/1.1: only one exchange at a time. For HTTP/2: multiple concurrent exchanges (multiplexing). + * + * @param request the HTTP request to execute + * @param options per-request options (e.g. {@link RequestOptions#expectContinue()}); never null + * @return a new exchange for this request + * @throws IOException if the connection is not in a valid state or network error occurs + * @throws IllegalStateException if connection is closed + */ + HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException; + + /** + * Protocol version of this connection. + * + * @return HTTP version (HTTP/1.1, HTTP/2, etc.) + */ + HttpVersion httpVersion(); + + /** + * Get the destination of the HTTP connection. + * + * @return the request route. + */ + Route route(); + + /** + * Get SSL session if this is a secure connection. + * + *

Provides access to negotiated cipher suite, TLS version, peer certificates, etc. + * + * @return SSLSession, or null if not using TLS + */ + SSLSession sslSession(); + + /** + * Get ALPN negotiated protocol if applicable. + * + * @return "h2", "http/1.1", or null if ALPN not used + */ + String negotiatedProtocol(); + + /** + * Check if connection is still usable for new requests. + * + *

This is meant to be a fast check suitable for frequent calls. For connections retrieved from a pool after + * being idle, use {@link #validateForReuse()} which performs more thorough checks. + * + * @return true if connection can be used for new exchanges + */ + boolean isActive(); + + /** + * Thorough validation to check if a pooled connection can be reused. + * + *

This is more expensive than {@link #isActive()} but catches connections that were closed by the server while + * idle in the pool. Should be called when retrieving a connection that has been idle. + * + *

The default implementation just calls {@link #isActive()}. + * + * @return true if connection is healthy and usable + */ + default boolean validateForReuse() { + return isActive(); + } + + /** + * Close the underlying transport. + * Any active exchanges will be terminated. + */ + @Override + void close() throws IOException; +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactory.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactory.java new file mode 100644 index 0000000000..855896be43 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactory.java @@ -0,0 +1,648 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.util.Timer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.ModifiableHttpRequest; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.HttpCredentials; +import software.amazon.smithy.java.http.client.ProxyConfiguration; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.dns.DnsResolver; +import software.amazon.smithy.java.http.client.h1.H1Connection; +import software.amazon.smithy.java.http.client.h2.H2Connection; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * Factory for creating HTTP connections. + * + *

Handles connection creation including: + *

    + *
  • DNS resolution with multi-IP failover
  • + *
  • TLS handshake and ALPN negotiation
  • + *
  • Proxy tunneling (HTTP and HTTPS proxies)
  • + *
  • Protocol selection (HTTP/1.1 vs HTTP/2)
  • + *
+ * + * @param sslParameters may be null + */ +record HttpConnectionFactory( + Duration connectTimeout, + Duration tlsNegotiationTimeout, + Duration readTimeout, + Duration writeTimeout, + SSLContext sslContext, + SSLParameters sslParameters, + TlsProvider tlsProvider, + HttpVersionPolicy versionPolicy, + DnsResolver dnsResolver, + List listeners, + boolean hasListeners, + HttpSocketFactory socketFactory, + Timer readTimer, + EpollConnector epollConnector, + int h2InitialWindowSize, + int h2MaxFrameSize, + int h2BufferSize, + int tlsReadBufferSize, + int tlsWriteBufferSize) { + + /** + * Create a new connection to the given route. + * + * @param route the route to connect to + * @param exchangeId opaque client-generated exchange id used to correlate listener events + * @param options per-request options; non-null connect/read timeout overrides take precedence + * over this factory's configured defaults for this connection + * @return a new HttpConnection + * @throws IOException if connection fails + */ + HttpConnection create(Route route, long exchangeId, RequestOptions options) throws IOException { + // Per-request connect/read timeout overrides apply to every socket/epoll/TLS step of this + // connection attempt. Because this type is a record whose connect logic reads connectTimeout/ + // readTimeout off `this`, the cleanest way to apply them everywhere (including the proxy tunnel) + // is to resolve a factory copy with those two fields overridden, then run the usual machinery. + HttpConnectionFactory factory = withOverrides(options); + if (route.usesProxy()) { + return factory.connectViaProxy(route, exchangeId); + } + + List addresses = factory.resolve(route.host(), exchangeId); + + IOException lastException = null; + for (InetAddress address : addresses) { + try { + return factory.connectToAddress(address, route, addresses, exchangeId); + } catch (IOException e) { + lastException = e; + dnsResolver.reportFailure(address); + } + } + + throw new IOException( + "Failed to connect to " + route.host() + " on any resolved IP (" + addresses.size() + " tried)", + lastException); + } + + // Returns this factory, or a copy with connectTimeout/readTimeout replaced by the request's non-null + // overrides. Only these two are per-request; all other fields (TLS, buffers, listeners, timers) are + // shared client config and are carried over unchanged. + private HttpConnectionFactory withOverrides(RequestOptions options) { + Duration connect = options.connectTimeout() != null ? options.connectTimeout() : connectTimeout; + Duration read = options.readTimeout() != null ? options.readTimeout() : readTimeout; + if (Objects.equals(connect, connectTimeout) && Objects.equals(read, readTimeout)) { + return this; + } + return new HttpConnectionFactory( + connect, + tlsNegotiationTimeout, + read, + writeTimeout, + sslContext, + sslParameters, + tlsProvider, + versionPolicy, + dnsResolver, + listeners, + hasListeners, + socketFactory, + readTimer, + epollConnector, + h2InitialWindowSize, + h2MaxFrameSize, + h2BufferSize, + tlsReadBufferSize, + tlsWriteBufferSize); + } + + private HttpConnection connectToAddress( + InetAddress address, + Route route, + List allEndpoints, + long exchangeId + ) throws IOException { + if (epollConnector != null) { + return route.isSecure() + ? connectEpollTls(address, route, exchangeId) + : connectEpollCleartext(address, route, exchangeId); + } + + Socket socket = socketFactory.newSocket(route, allEndpoints); + connectSocket(address, route, exchangeId, socket, route.port()); + + ConnectionTransport transport; + if (!route.isSecure()) { + transport = ConnectionTransport.of(socket); + } else { + transport = performTlsHandshake(socket, route, exchangeId); + } + + return createProtocolConnection(transport, route); + } + + private void connectSocket(InetAddress address, Route route, long exchangeId, Socket socket, int port) + throws IOException { + notifyConnectStart(exchangeId, route, address); + try { + socket.connect(new InetSocketAddress(address, port), toIntMillis(connectTimeout)); + notifyConnectEnd(exchangeId, route, address, null); + } catch (IOException | RuntimeException e) { + notifyConnectEnd(exchangeId, route, address, e); + // This helper closes the socket on connect failure so the direct path (which has no outer + // catch) does not leak it. Callers with an outer catch-all (the proxy path) may close it + // again; that is safe since closeQuietly and Socket.close are idempotent. + closeQuietly(socket); + throw e; + } + } + + private EpollChannel connectEpollChannel(InetAddress address, Route route, long exchangeId) throws IOException { + try { + notifyConnectStart(exchangeId, route, address); + try { + EpollChannel channel = epollConnector.connect(address, route.port(), toIntMillis(connectTimeout)); + notifyConnectEnd(exchangeId, route, address, null); + return channel; + } catch (IOException | RuntimeException e) { + notifyConnectEnd(exchangeId, route, address, e); + throw e; + } + } catch (IOException e) { + throw new IOException("Failed to connect to " + route.host() + " via epoll transport", e); + } + } + + private HttpConnection connectEpollCleartext(InetAddress address, Route route, long exchangeId) throws IOException { + EpollChannel channel = connectEpollChannel(address, route, exchangeId); + try { + return createProtocolConnection(new EpollTransport(channel, toIntMillis(readTimeout)), route); + } catch (IOException | RuntimeException e) { + channel.close(); + throw e; + } + } + + private HttpConnection connectEpollTls(InetAddress address, Route route, long exchangeId) throws IOException { + EpollChannel channel = connectEpollChannel(address, route, exchangeId); + + TlsConnectionContext connection = tlsConnection(route) + .epollChannel(channel) + // The negotiation deadline is honored by SSLEngineTransport's own timed-park read path + // (epoll has no SO_TIMEOUT); readTimeoutMillis is applied as the steady-state deadline. + .readTimeoutMillis(toIntMillis(readTimeout)) + .build(); + + notifyTlsStart(exchangeId, route); + ConnectionTransport transport; + try { + transport = tlsProvider.connect(connection); + } catch (IOException | RuntimeException e) { + // connect() already released the engine and closed the channel on failure. + notifyTlsEnd(exchangeId, route, null, e); + throw e; + } + notifyTlsEnd(exchangeId, route, transport, null); + return createProtocolConnection(transport, route); + } + + private ConnectionTransport performTlsHandshake(Socket socket, Route route, long exchangeId) throws IOException { + TlsConnectionContext connection = tlsConnection(route) + .socket(socket) + .readTimer(readTimer) + .build(); + + notifyTlsStart(exchangeId, route); + ConnectionTransport transport; + try { + transport = tlsProvider.connect(connection); + } catch (IOException | RuntimeException e) { + // connect() already released the engine and closed the socket on failure. + notifyTlsEnd(exchangeId, route, null, e); + throw e; + } + notifyTlsEnd(exchangeId, route, transport, null); + return transport; + } + + // Shared TlsConnectionContext skeleton (host/port/ALPN/negotiation deadline/buffer sizes); the caller + // adds the transport substrate (socket or epoll channel). + private TlsConnectionContext.Builder tlsConnection(Route route) { + return TlsConnectionContext.builder() + .host(route.host()) + .port(route.port()) + .alpnProtocols(List.of(versionPolicy.alpnProtocols())) + .negotiationTimeoutMillis(toIntMillis(tlsNegotiationTimeout)) + .tlsReadBufferSize(tlsReadBufferSize) + .tlsWriteBufferSize(tlsWriteBufferSize); + } + + // SSLParameters for the proxy-leg SSLSocket TLS (client -> https proxy). The target-leg TLS is + // handled by the TlsProvider; this configures only the connection to the proxy itself. + private SSLParameters socketParameters(SSLSocket sslSocket, String[] applicationProtocols) { + SSLParameters params = sslParameters != null + ? JdkTlsProvider.copyParameters(sslParameters) + : sslSocket.getSSLParameters(); + params.setEndpointIdentificationAlgorithm("HTTPS"); + if (applicationProtocols != null) { + params.setApplicationProtocols(applicationProtocols); + } + return params; + } + + enum Protocol { + H1, H2 + } + + private HttpConnection createProtocolConnection(ConnectionTransport transport, Route route) throws IOException { + try { + Protocol protocol = selectProtocol(transport.negotiatedProtocol(), route.isSecure(), versionPolicy); + return switch (protocol) { + case H2 -> createH2Connection(transport, route); + case H1 -> new H1Connection(transport, route, readTimeout); + }; + } catch (IOException e) { + try { + transport.close(); + } catch (IOException ignored) { + // ignored + } + throw e; + } + } + + static Protocol selectProtocol(String negotiated, boolean secure, HttpVersionPolicy policy) throws IOException { + if (negotiated != null && !negotiated.isEmpty()) { + return switch (negotiated) { + case "h2" -> { + if (policy == HttpVersionPolicy.ENFORCE_HTTP_1_1) { + throw new IOException("Server negotiated HTTP/2 but client is configured for HTTP/1.1 only"); + } + yield Protocol.H2; + } + case "http/1.1" -> { + if (policy == HttpVersionPolicy.ENFORCE_HTTP_2 || policy == HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) { + throw new IOException("Server negotiated HTTP/1.1 but client is configured for HTTP/2 only"); + } + yield Protocol.H1; + } + default -> throw new IOException("Unsupported negotiated protocol: " + negotiated); + }; + } + + if (secure) { + if (policy == HttpVersionPolicy.ENFORCE_HTTP_2 || policy == HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE) { + throw new IOException("No HTTP/2 protocol negotiated by TLS ALPN"); + } + return Protocol.H1; + } else if (policy.usesH2cForCleartext()) { + return Protocol.H2; + } else if (policy == HttpVersionPolicy.ENFORCE_HTTP_2) { + throw new IOException("HTTP/2 without TLS requires h2c prior knowledge"); + } else { + return Protocol.H1; + } + } + + private H2Connection createH2Connection(ConnectionTransport transport, Route route) throws IOException { + return new H2Connection(transport, + route, + readTimeout, + writeTimeout, + h2InitialWindowSize, + h2MaxFrameSize, + h2BufferSize); + } + + private HttpConnection connectViaProxy(Route route, long exchangeId) throws IOException { + ProxyConfiguration proxy = route.proxy(); + + if (proxy.type() == ProxyConfiguration.ProxyType.SOCKS4 + || proxy.type() == ProxyConfiguration.ProxyType.SOCKS5) { + // IOException (not UnsupportedOperationException) so the caller's per-proxy catch treats this + // as a route-attempt failure: ProxySelector.connectFailed runs and the next proxy is tried. + throw new IOException("SOCKS proxies not yet supported: " + proxy.type()); + } + + List proxyAddresses = resolve(proxy.hostname(), exchangeId); + + IOException lastException = null; + for (InetAddress proxyAddress : proxyAddresses) { + try { + return connectToProxy(proxyAddress, route, proxy, proxyAddresses, exchangeId); + } catch (IOException e) { + lastException = e; + dnsResolver.reportFailure(proxyAddress); + } + } + + throw new IOException( + "Failed to connect to proxy " + proxy.hostname() + " on any resolved IP (" + + proxyAddresses.size() + " tried)", + lastException); + } + + private HttpConnection connectToProxy( + InetAddress proxyAddress, + Route route, + ProxyConfiguration proxy, + List allProxyEndpoints, + long exchangeId + ) throws IOException { + Socket proxySocket = socketFactory.newSocket(route, allProxyEndpoints); + + try { + connectSocket(proxyAddress, route, exchangeId, proxySocket, proxy.port()); + + // Connect to the proxy over TLS if the scheme is https + if ("https".equalsIgnoreCase(proxy.proxyUri().getScheme())) { + // Use SSLSocket for proxy TLS; the tunnel itself does not need the SSLEngine path. + proxySocket = performTlsHandshakeToProxy(proxySocket, proxy); + } + + if (route.isSecure()) { + notifyProxyConnectStart(exchangeId, route, proxy, proxyAddress); + TunnelResult result; + try { + result = establishTunnel( + proxySocket, + route.host(), + route.port(), + proxy.credentials(), + readTimeout); + } catch (IOException | RuntimeException e) { + notifyProxyConnectEnd(exchangeId, route, proxy, proxyAddress, -1, e); + throw e; + } + + // A non-200 CONNECT is a tunnel failure, not a success: report it through the terminal + // event with an error (consistent with every other *End event) before throwing. + if (result.statusCode() != 200) { + var failure = new IOException("Proxy CONNECT failed: " + result.statusCode()); + notifyProxyConnectEnd(exchangeId, route, proxy, proxyAddress, result.statusCode(), failure); + closeQuietly(proxySocket); + throw failure; + } + notifyProxyConnectEnd(exchangeId, route, proxy, proxyAddress, result.statusCode(), null); + + // The TLS provider owns the end-to-end handshake to the target through the tunnel. (The + // JDK provider still picks its SSLSocket fast path internally for HTTP/1.1.) + ConnectionTransport transport = performTlsHandshake(proxySocket, route, exchangeId); + return createProtocolConnection(transport, route); + } + + return createProtocolConnection(ConnectionTransport.of(proxySocket), route); + } catch (IOException e) { + closeQuietly(proxySocket); + throw new IOException( + "Failed to connect to " + route.host() + " via proxy " + + proxy.hostname() + ":" + proxy.port() + " (" + proxyAddress.getHostAddress() + ")", + e); + } + } + + record TunnelResult(Socket socket, int statusCode, HttpHeaders headers) {} + + static TunnelResult establishTunnel( + Socket proxySocket, + String targetHost, + int targetPort, + HttpCredentials credentials, + Duration readTimeout + ) throws IOException { + Route proxyRoute = Route.direct( + "http", + proxySocket.getInetAddress().getHostAddress(), + proxySocket.getPort()); + H1Connection conn = new H1Connection(ConnectionTransport.of(proxySocket), proxyRoute, readTimeout); + + HttpResponse priorResponse = null; + + do { + String authority = targetHost + ":" + targetPort; + ModifiableHttpRequest connectRequest = HttpRequest.create() + .setMethod("CONNECT") + .setUri(SmithyUri.of("http://" + authority)) + .addHeader("Host", authority) + .addHeader("Proxy-Connection", "Keep-Alive"); + + if (credentials != null) { + boolean applied = credentials.authenticate(connectRequest, priorResponse); + if (!applied && priorResponse != null) { + break; + } + } + + // The CONNECT tunnel handshake carries no per-request overrides of its own. + var exchange = conn.newExchange(connectRequest, RequestOptions.defaults()); + exchange.writeRequestBody(null); + + int status = exchange.responseStatusCode(); + HttpHeaders headers = exchange.responseHeaders(); + + if (status == 200) { + return new TunnelResult(proxySocket, status, headers); + } + + try (var body = exchange.responseBody()) { + body.transferTo(OutputStream.nullOutputStream()); + } + + priorResponse = HttpResponse.create() + .setStatusCode(status) + .setHeaders(headers); + + } while (priorResponse.statusCode() == 407 && credentials != null); + + return new TunnelResult(null, priorResponse.statusCode(), priorResponse.headers()); + } + + private Socket performTlsHandshakeToProxy(Socket socket, ProxyConfiguration proxy) throws IOException { + SSLSocket sslSocket = null; + try { + sslSocket = (SSLSocket) sslContext.getSocketFactory() + .createSocket(socket, proxy.hostname(), proxy.port(), true); + sslSocket.setSSLParameters(socketParameters(sslSocket, null)); + + int originalTimeout = sslSocket.getSoTimeout(); + sslSocket.setSoTimeout(toIntMillis(tlsNegotiationTimeout)); + try { + sslSocket.startHandshake(); + } finally { + sslSocket.setSoTimeout(originalTimeout); + } + + return sslSocket; + } catch (IOException e) { + closeQuietly(sslSocket != null ? sslSocket : socket); + throw new IOException("TLS handshake to HTTPS proxy " + proxy.hostname() + " failed", e); + } + } + + private List resolve(String host, long exchangeId) throws IOException { + notifyDnsStart(exchangeId, host); + try { + List addresses = dnsResolver.resolve(host); + // An empty result is a DNS failure indistinguishable from a thrown one: both mean no usable + // address. Report it as such (onDnsEnd with an error) rather than firing a success event and + // letting the caller discover emptiness afterwards. + if (addresses.isEmpty()) { + throw new IOException("DNS resolution failed: no addresses for " + host); + } + notifyDnsEnd(exchangeId, host, addresses, null); + return addresses; + } catch (IOException | RuntimeException e) { + notifyDnsEnd(exchangeId, host, List.of(), e); + throw e; + } + } + + private void notifyDnsStart(long exchangeId, String host) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onDnsStart(exchangeId, host); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onDnsStart", e); + } + } + } + } + + private void notifyDnsEnd(long exchangeId, String host, List addresses, Throwable error) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onDnsEnd(exchangeId, host, addresses, error); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onDnsEnd", e); + } + } + } + } + + private void notifyConnectStart(long exchangeId, Route route, InetAddress address) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectStart(exchangeId, route, address); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectStart", e); + } + } + } + } + + private void notifyConnectEnd(long exchangeId, Route route, InetAddress address, Throwable error) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectEnd(exchangeId, route, address, error); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectEnd", e); + } + } + } + } + + private void notifyTlsStart(long exchangeId, Route route) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onTlsStart(exchangeId, route); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onTlsStart", e); + } + } + } + } + + private void notifyTlsEnd(long exchangeId, Route route, ConnectionTransport transport, Throwable error) { + String cipherSuite = null; + if (transport != null && transport.sslSession() != null) { + cipherSuite = transport.sslSession().getCipherSuite(); + } + notifyTlsEnd(exchangeId, route, transport == null ? null : transport.negotiatedProtocol(), cipherSuite, error); + } + + private void notifyTlsEnd( + long exchangeId, + Route route, + String protocol, + String cipherSuite, + Throwable error + ) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onTlsEnd(exchangeId, route, protocol, cipherSuite, error); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onTlsEnd", e); + } + } + } + } + + private void notifyProxyConnectStart(long exchangeId, Route route, ProxyConfiguration proxy, InetAddress address) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onProxyConnectStart(exchangeId, route, proxy, address); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onProxyConnectStart", e); + } + } + } + } + + private void notifyProxyConnectEnd( + long exchangeId, + Route route, + ProxyConfiguration proxy, + InetAddress address, + int statusCode, + Throwable error + ) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onProxyConnectEnd(exchangeId, route, proxy, address, statusCode, error); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onProxyConnectEnd", e); + } + } + } + } + + /** + * Convert Duration to int milliseconds, clamping to Integer.MAX_VALUE to avoid overflow. + */ + private static int toIntMillis(Duration d) { + long ms = d.toMillis(); + return ms > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) ms; + } + + private static void closeQuietly(Socket socket) { + try { + socket.close(); + } catch (IOException ignored) { + // ignored + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPool.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPool.java new file mode 100644 index 0000000000..7d52b5ba5e --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPool.java @@ -0,0 +1,598 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.concurrent.DefaultThreadFactory; +import java.io.IOException; +import java.net.Socket; +import java.nio.channels.SocketChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.dns.DnsResolver; + +/** + * HTTP connection pool optimized for virtual threads. + * + *

Manages connection lifecycle including: + *

    + *
  • Connection creation with configured SSLContext and version policy
  • + *
  • Connection reuse via pooling (keyed by {@link Route})
  • + *
  • Health monitoring and stale connection cleanup
  • + *
  • DNS resolution with multi-IP failover
  • + *
  • Per-route connection limits with host-specific overrides
  • + *
+ * + *

Thread Safety

+ *

This class is thread-safe for concurrent access. Multiple virtual threads + * can safely acquire and release connections simultaneously. + * + *

Connection Pooling Strategy

+ *

Connections are pooled by {@link Route}, which represents a unique + * destination (scheme + host + port + proxy). Two requests to different paths + * on the same host will share connections: + * + *

{@code
+ * Route route1 = Route.from(SmithyUri.of("https://api.example.com/users"));
+ * Route route2 = Route.from(SmithyUri.of("https://api.example.com/posts"));
+ * // route1.equals(route2) == true, so connections are shared
+ * }
+ * + *

Per-Route Connection Limits

+ *

You can set different connection limits for different hosts: + * + *

Connection limits are configured through {@link ConnectionConfig}. Most callers should set them on + * {@link software.amazon.smithy.java.http.client.HttpClient.Builder}, which creates the config and default pool. + * + *

Health Monitoring

+ *

A background virtual thread runs every 30 seconds to remove idle and + * unhealthy connections from the pool. Connections are considered stale if: + *

    + *
  • They've been idle longer than {@code maxIdleTime}
  • + *
  • The underlying socket is closed
  • + *
  • {@link HttpConnection#isActive()} returns false
  • + *
+ * + *

DNS Resolution and Failover

+ *

When creating new connections, the pool resolves hostnames to IP addresses + * using the configured {@link DnsResolver}. If resolution returns multiple IPs, + * the pool attempts to connect to each one until successful: + * + *

{@code
+ * // api.example.com resolves to [203.0.113.1, 203.0.113.2]
+ * // If connection to .1 fails, automatically tries .2
+ * HttpConnection conn = pool.acquire(route, exchangeId);
+ * }
+ * + *

Pool Exhaustion and Backpressure

+ *

When route capacity, stream capacity, or {@code maxTotalConnections} is exhausted, + * {@link #acquire} blocks for up to {@code acquireTimeout} (default: 30 seconds) + * waiting for capacity to become available. This behavior is consistent for both HTTP/1.1 + * and HTTP/2 connections. + * + *

The blocking wait is on the global physical-connection semaphore, so callers + * unblock when an open connection is closed and releases capacity. With virtual + * threads, this blocking is cheap and provides natural backpressure under load. + * + *

Configure via {@link software.amazon.smithy.java.http.client.HttpClient.Builder#acquireTimeout(Duration)}: + *

    + *
  • Default (30s): Good backpressure for load spikes, requests queue briefly
  • + *
  • {@link Duration#ZERO}: Fail-fast behavior, immediate failure when exhausted
  • + *
  • Longer timeout: More tolerance for sustained high load
  • + *
+ * + *

Example Usage

+ *
{@code
+ * // Create pool directly when implementing a custom client/pool factory.
+ * ConnectionConfig config = ConnectionConfig.builder()
+ *     .maxConnectionsPerRoute(20)
+ *     .maxTotalConnections(200)
+ *     .maxIdleTime(Duration.ofMinutes(2))
+ *     .sslContext(customSSLContext)
+ *     .httpVersionPolicy(HttpVersionPolicy.AUTOMATIC)
+ *     .build();
+ * HttpConnectionPool pool = new HttpConnectionPool(config);
+ *
+ * // Acquire connection
+ * Route route = Route.from(SmithyUri.of("https://api.example.com/users"));
+ * HttpConnection conn = pool.acquire(route, exchangeId);
+ *
+ * try {
+ *     // Use connection
+ *     HttpExchange exchange = conn.newExchange(request);
+ *     // ...
+ * } finally {
+ *     // Return to pool for reuse
+ *     pool.release(conn);
+ * }
+ *
+ * // Cleanup
+ * pool.close();
+ * }
+ * + * @see Route + * @see HttpConnection + * @see HttpVersionPolicy + */ +public final class HttpConnectionPool implements ConnectionPool { + + private final int maxConnectionsPerRoute; + private final int maxTotalConnections; + private final long acquireTimeoutMs; // Timeout for acquiring a connection when pool is exhausted + private final long maxIdleTimeNanos; // Max idle time before closing connections + private final HttpVersionPolicy versionPolicy; + private final HttpConnectionFactory connectionFactory; + + // HTTP/1.1 connection manager (handles pooling) + private final H1ConnectionManager h1Manager; + + // HTTP/2 connection manager (handles multiplexing) + private final H2ConnectionManager h2Manager; + + // Semaphore to limit total open physical connections - better contention than AtomicInteger CAS loop. + // H1 idle sockets hold permits while pooled; H2 sockets hold permits until closed. + private final Semaphore connectionPermits; + + // Cleanup thread + private final Thread cleanupThread; + private volatile boolean closed = false; + + // Shared single-thread watchdog enforcing read deadlines for the SSLEngineTransport channel path. + // A blocking SocketChannel.read ignores SO_TIMEOUT, so instead of opening an epoll Selector per + // read (epoll_create1/eventfd/close churn) the read parks the VT and this timer closes the channel + // if the deadline passes. One wheel for the whole pool, giving O(1) arm/cancel per read. + private final HashedWheelTimer readTimer; + + // Listeners for client lifecycle events + private final List listeners; + private final boolean hasListeners; + + public HttpConnectionPool(ConnectionConfig config) { + this.maxConnectionsPerRoute = config.maxConnectionsPerRoute(); + this.maxTotalConnections = config.maxTotalConnections(); + // Cached to avoid Duration.toNanos() in hot path + this.maxIdleTimeNanos = config.maxIdleTime().toNanos(); + this.acquireTimeoutMs = config.acquireTimeout().toMillis(); + this.versionPolicy = config.versionPolicy(); + DnsResolver dnsResolver = config.dnsResolver() != null ? config.dnsResolver() : DnsResolver.roundRobin(); + + this.readTimer = new HashedWheelTimer( + new DefaultThreadFactory("smithy-http-read-timeout", true), + 100, + TimeUnit.MILLISECONDS); + + this.listeners = config.listeners(); + this.hasListeners = !listeners.isEmpty(); + + TlsProvider tls = resolveTls(config); + + // Use the epoll backend only when the native library is available AND the resolved TLS provider + // supports it AND the user has not supplied a custom socket factory. The epoll path hands the + // provider a null-socket context whose byte channel is consumable only by engine-based providers + // (via SslEngineTransports); a provider that does its own socket I/O (supportsEpoll() == false) + // must get the NIO socket path so socket() is non-null. Note: this also routes cleartext + // connections on such a client through NIO, which is acceptable, since a custom TLS provider is + // configured for secure traffic. A custom socketFactory likewise forces the NIO path: the epoll + // connector creates its own channels and would otherwise silently bypass the user's factory. + EpollConnector epollConnector = tls.supportsEpoll() && config.socketFactory() == null + ? EpollConnector.createIfAvailable( + config.socketReceiveBufferSize(), + config.socketSendBufferSize(), + readTimer) + : null; + + this.connectionFactory = new HttpConnectionFactory( + config.connectTimeout(), + config.tlsNegotiationTimeout(), + config.readTimeout(), + config.writeTimeout(), + config.sslContext(), + config.sslParameters(), + tls, + config.versionPolicy(), + dnsResolver, + listeners, + !listeners.isEmpty(), + resolveSocketFactory(config), + readTimer, + epollConnector, + config.h2InitialWindowSize(), + config.h2MaxFrameSize(), + config.h2BufferSize(), + config.tlsReadBufferSize(), + config.tlsWriteBufferSize()); + + this.h1Manager = new H1ConnectionManager(this.maxIdleTimeNanos); + this.connectionPermits = new Semaphore(config.maxTotalConnections(), false); + this.h2Manager = new H2ConnectionManager(config.h2StreamsPerConnection(), + this.acquireTimeoutMs, + listeners, + this::onNewH2Connection); + this.cleanupThread = Thread.ofVirtual().name("http-pool-cleanup").start(this::cleanupIdleConnections); + } + + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) throws IOException { + if (closed) { + throw new IllegalStateException("Connection pool is closed"); + } else if ((route.isSecure() && versionPolicy != HttpVersionPolicy.ENFORCE_HTTP_1_1) + || (!route.isSecure() && versionPolicy.usesH2cForCleartext())) { + return h2Manager.acquire(route, maxConnectionsPerRoute, exchangeId, options); + } else { + return acquireH1(route, exchangeId, options); + } + } + + // Per-request acquire timeout override falls back to the pool default. + private long acquireTimeoutMs(RequestOptions options) { + return options.acquireTimeout() != null ? options.acquireTimeout().toMillis() : acquireTimeoutMs; + } + + private HttpConnection acquireH1(Route route, long exchangeId, RequestOptions options) throws IOException { + int maxConns = maxConnectionsPerRoute; + long timeoutMs = acquireTimeoutMs(options); + + h1Manager.acquireActive(route, maxConns, timeoutMs); + + try { + // Idle H1 connections already hold a global connection permit. + HttpConnection pooled = h1Manager.tryAcquire(route, maxConns, this::releaseIdleH1Permit); + if (pooled != null) { + notifyAcquire(pooled, true); + return pooled; + } + + // No pooled connection, so acquire global capacity for a new physical socket. + acquirePermit(timeoutMs); + + // Re-check the pool: a connection may have been released while we waited. If we reuse one, + // give back the just-acquired permit since the idle socket already owns one. + pooled = h1Manager.tryAcquire(route, maxConns, this::releaseIdleH1Permit); + if (pooled != null) { + connectionPermits.release(); + notifyAcquire(pooled, true); + return pooled; + } + + return createH1Connection(route, exchangeId, options); + } catch (IOException | RuntimeException e) { + h1Manager.releaseActive(route); + throw e; + } + } + + private HttpConnection createH1Connection(Route route, long exchangeId, RequestOptions options) throws IOException { + HttpConnection conn = null; + boolean success = false; + try { + conn = connectionFactory.create(route, exchangeId, options); + notifyConnected(conn); + notifyAcquire(conn, false); + success = true; + return conn; + } catch (Exception e) { + if (e instanceof IOException ioe) { + throw ioe; + } + throw new IOException(e); + } finally { + if (!success) { + connectionPermits.release(); + if (conn != null) { + closeConnection(conn); + } + } + } + } + + // Called by H2ConnectionManager when a new connection is needed. + private MultiplexedHttpConnection onNewH2Connection(Route route, long exchangeId, RequestOptions options) + throws IOException { + // Dead-connection cleanup is left to the background thread; doing it here caused lock contention. + acquirePermit(acquireTimeoutMs(options)); + + HttpConnection conn = null; + boolean success = false; + try { + conn = connectionFactory.create(route, exchangeId, options); + notifyConnected(conn); + if (conn instanceof MultiplexedHttpConnection h2conn) { + success = true; + return h2conn; + } + // ALPN negotiated HTTP/1.1 instead of H2 - shouldn't happen with H2C_PRIOR_KNOWLEDGE + throw new IOException("Expected H2 connection but got " + conn.httpVersion()); + } catch (Exception e) { + if (e instanceof IOException ioe) { + throw ioe; + } + throw new IOException(e); + } finally { + if (!success) { + connectionPermits.release(); + if (conn != null) { + closeConnection(conn); + } + } + } + } + + /** + * Acquire a connection permit, blocking up to acquireTimeout. + */ + private void acquirePermit(long timeoutMs) throws IOException { + try { + if (!connectionPermits.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { + throw new IOException("Connection pool exhausted: " + maxTotalConnections + + " connections in use (timed out after " + timeoutMs + "ms)"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while waiting for connection", e); + } + } + + @Override + public void release(HttpConnection connection) { + Objects.requireNonNull(connection, "connection cannot be null"); + Route route = connection.route(); + + notifyReturn(connection); + + // H2 connections stay active for multiplexing - don't pool them + if (connection instanceof MultiplexedHttpConnection h2conn) { + if (!connection.isActive() || closed) { + h2Manager.unregister(route, h2conn); + closeAndReleasePermit(connection, CloseReason.UNEXPECTED_CLOSE); + } + return; + } + + if (!h1Manager.release(route, connection, closed)) { + closeAndReleasePermit(connection, CloseReason.POOL_FULL); + } + } + + @Override + public void evict(HttpConnection connection, boolean isError) { + Objects.requireNonNull(connection, "connection cannot be null"); + Route route = connection.route(); + + if (connection instanceof MultiplexedHttpConnection h2conn) { + h2Manager.unregister(route, h2conn); + } else { + h1Manager.remove(route, connection); + h1Manager.releaseActive(route); + } + + closeAndReleasePermit(connection, isError ? CloseReason.ERRORED : CloseReason.EVICTED); + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + + closed = true; + cleanupThread.interrupt(); + readTimer.stop(); + + List exceptions = new ArrayList<>(); + + // Close active H2 connections + h2Manager.closeAll((conn, reason) -> { + try { + conn.close(); + } catch (IOException e) { + exceptions.add(e); + } + notifyClosed(conn, CloseReason.POOL_SHUTDOWN); + }); + + // Close pooled H1 connections + h1Manager.closeAll(exceptions, conn -> { + notifyClosed(conn, CloseReason.POOL_SHUTDOWN); + connectionPermits.release(); + }); + + if (!exceptions.isEmpty()) { + IOException e = new IOException("Errors closing connections"); + exceptions.forEach(e::addSuppressed); + throw e; + } + } + + @Override + public void shutdown(Duration gracePeriod) throws IOException { + Objects.requireNonNull(gracePeriod, "gracePeriod cannot be null"); + + if (closed) { + return; + } + + closed = true; // Stop new acquires + cleanupThread.interrupt(); + readTimer.stop(); + + // Wait for connections to be closed (permits represent physical connections, not streams). + // For HTTP/2, permits are released when the connection closes, not when streams finish. + Instant deadline = Instant.now().plus(gracePeriod); + while (connectionPermits.availablePermits() < maxTotalConnections && Instant.now().isBefore(deadline)) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + // Force close remaining + close(); + } + + /** + * Close a connection, ignoring any IOException. + * + * @param connection the connection to close + */ + private void closeConnection(HttpConnection connection) { + try { + connection.close(); + } catch (IOException ignored) { + // best effort + } + } + + /** + * Close a connection, notify listeners, and release its permit. + */ + private void closeAndReleasePermit(HttpConnection connection, CloseReason reason) { + try { + closeConnection(connection); + notifyClosed(connection, reason); + } finally { + // Release the permit unconditionally: a listener (or close) failure must never leak a + // permit, or the pool slowly exhausts and every acquire eventually blocks. + connectionPermits.release(); + } + } + + private void notifyConnected(HttpConnection connection) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectionCreated(connection); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectionCreated", e); + } + } + } + } + + private void notifyAcquire(HttpConnection connection, boolean reused) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectionAcquired(connection, reused); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectionAcquired", e); + } + } + } + } + + private void notifyReturn(HttpConnection connection) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectionReturned(connection); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectionReturned", e); + } + } + } + } + + private void notifyClosed(HttpConnection connection, CloseReason reason) { + if (hasListeners) { + for (HttpClientListener listener : listeners) { + try { + listener.onConnectionClosed(connection, reason); + } catch (Throwable e) { + ListenerSupport.listenerFailed("onConnectionClosed", e); + } + } + } + } + + private void releaseIdleH1Permit(HttpConnection connection, CloseReason reason) { + try { + notifyClosed(connection, reason); + } finally { + connectionPermits.release(); + } + } + + /** + * Background cleanup task that runs every 30 seconds. + * + *

For HTTP/1.1 connections, removes connections that: + *

    + *
  • Have been idle longer than {@code maxIdleTime}
  • + *
  • Are no longer active ({@link HttpConnection#isActive()} is false)
  • + *
+ * + *

For HTTP/2 connections, removes connections that: + *

    + *
  • Are no longer active or can't accept more streams
  • + *
  • Have no active streams and have been idle longer than {@code maxIdleTime}
  • + *
+ * + *

Runs on a virtual thread, so blocking is cheap. + */ + private void cleanupIdleConnections() { + while (!closed) { + try { + Thread.sleep(Duration.ofSeconds(30)); + h1Manager.cleanupIdle(this::releaseIdleH1Permit); + h2Manager.cleanupAllDead(this::closeAndReleasePermit); + h2Manager.cleanupIdle(maxIdleTimeNanos, this::closeAndReleasePermit); + } catch (InterruptedException e) { + break; + } + } + } + + // Resolve once per pool: an explicit provider from the config wins; otherwise an opt-in provider + // selected by the smithy-java.tls-provider system property; otherwise the built-in JDK provider + // configured from the convenience sslContext/sslParameters. The JDK provider picks its own + // SSLSocket-vs-SSLEngine strategy per connection. + private static TlsProvider resolveTls(ConnectionConfig config) { + if (config.tlsProvider() != null) { + return config.tlsProvider(); + } + var discovered = TlsProvider.fromSystemProperty(); + if (discovered != null) { + return discovered; + } + return JdkTlsProvider.builder() + .sslContext(config.sslContext()) + .sslParameters(config.sslParameters()) + .build(); + } + + private static HttpSocketFactory resolveSocketFactory(ConnectionConfig config) { + // A user-supplied factory is honored verbatim. + if (config.socketFactory() != null) { + return config.socketFactory(); + } + Integer recv = config.socketReceiveBufferSize(); + Integer send = config.socketSendBufferSize(); + if (recv == null && send == null) { + return HttpSocketFactory.DEFAULT; + } + return (route, endpoints) -> { + Socket socket = SocketChannel.open().socket(); + socket.setTcpNoDelay(true); + socket.setKeepAlive(true); + if (send != null && send != -1) { + socket.setSendBufferSize(send); + } + if (recv != null && recv != -1) { + socket.setReceiveBufferSize(recv); + } + return socket; + }; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpSocketFactory.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpSocketFactory.java new file mode 100644 index 0000000000..918b2034de --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpSocketFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.nio.channels.SocketChannel; +import java.util.List; + +/** + * Factory for creating sockets used by the connection pool, allowing for customizing socket options. + * + *

The socket returned should be unconnected. The pool will call {@link Socket#connect} after receiving the socket + * from this factory. + * + *

Example

+ * {@snippet : + * HttpClient client = HttpClient.builder() + * .socketFactory((route, endpoints) -> { + * Socket socket = new Socket(); + * socket.setTcpNoDelay(true); + * socket.setKeepAlive(true); + * if (route.host().endsWith(".internal")) { + * socket.setSendBufferSize(256 * 1024); + * } + * return socket; + * }) + * .build(); + * } + * + * @see software.amazon.smithy.java.http.client.HttpClient.Builder#socketFactory(HttpSocketFactory) + */ +@FunctionalInterface +public interface HttpSocketFactory { + /** + * Create a new unconnected socket for the given route. + * + * @param route the target route (host, port, secure flag) + * @param endpoints the resolved IP addresses for the route's host, in preference order + * @return a new unconnected socket + */ + Socket newSocket(Route route, List endpoints) throws IOException; + + /** + * Default factory that creates sockets with TCP_NODELAY=true and SO_KEEPALIVE=true. + * + *

TCP send and receive buffer sizes are left unset so the kernel can autotune them. + */ + HttpSocketFactory DEFAULT = (route, endpoints) -> { + Socket socket = SocketChannel.open().socket(); + socket.setTcpNoDelay(true); + socket.setKeepAlive(true); + return socket; + }; +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpVersionPolicy.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpVersionPolicy.java new file mode 100644 index 0000000000..46e10bc5b3 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/HttpVersionPolicy.java @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +/** + * HTTP protocol version policy for connection negotiation. + */ +public enum HttpVersionPolicy { + /** HTTP/1.1 only. For TLS, negotiates only "http/1.1" via ALPN. */ + ENFORCE_HTTP_1_1(new String[] {"http/1.1"}), + + /** HTTP/2 over TLS only. Negotiates only "h2" via ALPN. Fails if server doesn't support. */ + ENFORCE_HTTP_2(new String[] {"h2"}), + + /** Prefer HTTP/2, fall back to HTTP/1.1. Uses HTTP/1.1 for cleartext. Recommended default. */ + AUTOMATIC(new String[] {"h2", "http/1.1"}), + + /** HTTP/2 over cleartext (h2c) using prior knowledge. */ + H2C_PRIOR_KNOWLEDGE(new String[] {"h2"}); + + private final String[] alpnProtocols; + + HttpVersionPolicy(String[] alpnProtocols) { + this.alpnProtocols = alpnProtocols; + } + + /** + * Get ALPN protocol strings for this policy. + * + *

Only applicable for TLS connections. For cleartext, use {@link #usesH2cForCleartext()}. + * + * @return array of ALPN protocol strings in preference order + */ + public String[] alpnProtocols() { + return alpnProtocols.clone(); + } + + /** + * Check if this policy uses h2c (HTTP/2 cleartext) for non-TLS connections. + * + * @return true if h2c prior knowledge should be used for cleartext + */ + public boolean usesH2cForCleartext() { + return this == H2C_PRIOR_KNOWLEDGE; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/JdkTlsProvider.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/JdkTlsProvider.java new file mode 100644 index 0000000000..92941c645b --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/JdkTlsProvider.java @@ -0,0 +1,203 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.net.Socket; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; + +/** + * The built-in {@link TlsProvider} backed by the JDK's {@code javax.net.ssl} stack. + * + *

It uses two strategies, both producing a standard {@link ConnectionTransport}: + *

    + *
  • SSLSocket for an HTTP/1.1-only connection on a plain socket (no epoll): a blocking + * {@link SSLSocket} read/written directly, which is cheaper than the {@code SSLEngine} + * wrap/unwrap loop and is the common case for HTTP/1.1 services.
  • + *
  • SSLEngine (via {@link SslEngineTransports}) otherwise, such as for HTTP/2 / ALPN negotiation, or + * the epoll backend, where the engine drives TLS over the byte channel.
  • + *
+ * + *

This is the default provider when none is selected, and the target of the convenience + * {@code HttpClient.Builder.sslContext(...)} / {@code sslParameters(...)} setters: those build a + * {@code JdkTlsProvider} implicitly, equivalent to selecting one explicitly via + * {@code tlsProvider(JdkTlsProvider.builder().sslContext(...).sslParameters(...).build())}. + */ +public final class JdkTlsProvider implements TlsProvider { + + private static final List HTTP1_ONLY = List.of("http/1.1"); + + private final SSLContext sslContext; + private final SSLParameters sslParameters; + + private JdkTlsProvider(Builder builder) { + this.sslContext = builder.sslContext != null ? builder.sslContext : defaultContext(); + this.sslParameters = builder.sslParameters; + } + + /** + * @return a JDK provider using the default {@link SSLContext} and no custom parameters. + */ + public static JdkTlsProvider create() { + return builder().build(); + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public ConnectionTransport connect(TlsConnectionContext context) throws IOException { + // SSLSocket fast path: HTTP/1.1-only over a plain socket (the epoll backend has no socket and is + // driven through the engine instead). Cheaper than the SSLEngine wrap/unwrap loop. + if (context.socket() != null && HTTP1_ONLY.equals(context.alpnProtocols())) { + return connectSslSocket(context); + } + // Engine creation can fail before SslEngineTransports.connect takes ownership of the substrate + // (e.g. invalid SSLParameters -> IllegalArgumentException). The TlsProvider contract requires + // releasing the supplied socket/channel on failure, so close it before rethrowing. + SSLEngine engine; + try { + engine = createEngine(context.host(), context.port(), context.alpnProtocols()); + } catch (RuntimeException e) { + closeSubstrate(context); + throw e; + } + // The JDK engine holds no native resources, so there is nothing to release on close. + return SslEngineTransports.connect(context, engine, null); + } + + // Close whichever transport substrate the context carries (socket or internal epoll channel), + // honoring the TlsProvider contract that connect() releases it on failure. + private static void closeSubstrate(TlsConnectionContext context) { + if (context.socket() != null) { + closeQuietly(context.socket()); + } else if (context.epollChannel() != null) { + context.epollChannel().close(); + } + } + + @Override + public boolean supportsEpoll() { + // Engine-based path: SslEngineTransports consumes the internal epoll channel directly. + return true; + } + + private ConnectionTransport connectSslSocket(TlsConnectionContext context) throws IOException { + var socket = context.socket(); + SSLSocket sslSocket = null; + try { + sslSocket = (SSLSocket) sslContext.getSocketFactory() + .createSocket(socket, context.host(), context.port(), true); + + SSLParameters params = sslParameters != null ? copyParameters(sslParameters) + : sslSocket.getSSLParameters(); + params.setEndpointIdentificationAlgorithm("HTTPS"); + params.setApplicationProtocols(context.alpnProtocols().toArray(new String[0])); + sslSocket.setSSLParameters(params); + + int originalTimeout = sslSocket.getSoTimeout(); + sslSocket.setSoTimeout(context.negotiationTimeoutMillis()); + try { + sslSocket.startHandshake(); + } finally { + sslSocket.setSoTimeout(originalTimeout); + } + return ConnectionTransport.of(sslSocket); + } catch (IOException e) { + closeQuietly(sslSocket != null ? sslSocket : socket); + throw new IOException("TLS handshake failed for " + context.host(), e); + } catch (RuntimeException e) { + // e.g. invalid SSLParameters from setSSLParameters; release the socket before rethrowing. + closeQuietly(sslSocket != null ? sslSocket : socket); + throw e; + } + } + + private static void closeQuietly(Socket socket) { + try { + if (socket != null) { + socket.close(); + } + } catch (IOException ignored) { + // ignored + } + } + + private SSLEngine createEngine(String host, int port, List alpnProtocols) { + SSLEngine engine = sslContext.createSSLEngine(host, port); + engine.setUseClientMode(true); + + SSLParameters params = sslParameters != null ? copyParameters(sslParameters) : engine.getSSLParameters(); + params.setEndpointIdentificationAlgorithm("HTTPS"); + params.setApplicationProtocols(alpnProtocols.toArray(new String[0])); + engine.setSSLParameters(params); + return engine; + } + + private static SSLContext defaultContext() { + try { + return SSLContext.getDefault(); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Failed to get default SSLContext", e); + } + } + + // Deep-copy SSLParameters so per-connection mutation (endpoint id, ALPN) does not alter the shared + // user-supplied instance. Used by both the SSLSocket and SSLEngine strategies here, and by the + // factory's proxy-leg TLS so all JDK TLS paths copy the same full set of fields. + static SSLParameters copyParameters(SSLParameters src) { + SSLParameters dst = new SSLParameters(); + dst.setCipherSuites(src.getCipherSuites()); + dst.setProtocols(src.getProtocols()); + dst.setWantClientAuth(src.getWantClientAuth()); + dst.setNeedClientAuth(src.getNeedClientAuth()); + dst.setAlgorithmConstraints(src.getAlgorithmConstraints()); + dst.setEndpointIdentificationAlgorithm(src.getEndpointIdentificationAlgorithm()); + dst.setServerNames(src.getServerNames()); + dst.setSNIMatchers(src.getSNIMatchers()); + dst.setUseCipherSuitesOrder(src.getUseCipherSuitesOrder()); + dst.setEnableRetransmissions(src.getEnableRetransmissions()); + dst.setMaximumPacketSize(src.getMaximumPacketSize()); + dst.setApplicationProtocols(src.getApplicationProtocols()); + return dst; + } + + public static final class Builder { + private SSLContext sslContext; + private SSLParameters sslParameters; + + private Builder() {} + + /** + * @param sslContext the SSL context, or null to use {@link SSLContext#getDefault()} + * @return this builder + */ + public Builder sslContext(SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + + /** + * @param sslParameters custom parameters (cipher suites, protocols, SNI, ...), or null for the + * context defaults + * @return this builder + */ + public Builder sslParameters(SSLParameters sslParameters) { + this.sslParameters = sslParameters; + return this; + } + + public JdkTlsProvider build() { + return new JdkTlsProvider(this); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ListenerSupport.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ListenerSupport.java new file mode 100644 index 0000000000..5ceb31d050 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/ListenerSupport.java @@ -0,0 +1,21 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import software.amazon.smithy.java.logging.InternalLogger; + +final class ListenerSupport { + private static final InternalLogger LOGGER = InternalLogger.getLogger(ListenerSupport.class); + + private ListenerSupport() {} + + static void listenerFailed(String event, Throwable error) { + if (error instanceof VirtualMachineError) { + throw (VirtualMachineError) error; + } + LOGGER.warn("HTTP client listener failed in {}", event, error); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/MultiplexedHttpConnection.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/MultiplexedHttpConnection.java new file mode 100644 index 0000000000..6f23aff07d --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/MultiplexedHttpConnection.java @@ -0,0 +1,35 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +/** + * Internal connection-pool surface for multiplexed HTTP connections. + * + *

This is currently used by the HTTP/2 pool path so it can manage both the + * legacy {@code H2Connection} and alternate H2 implementations behind the same + * load-balancing and lifecycle code. + */ +public interface MultiplexedHttpConnection extends HttpConnection { + /** + * Set a callback to invoke when stream capacity becomes available again. + */ + void setStreamReleaseCallback(Runnable callback); + + /** + * Fast check for whether this connection can accept new streams. + */ + boolean canAcceptMoreStreams(); + + /** + * Get the active stream count if this connection can accept more streams, or -1 if not. + */ + int getActiveStreamCountIfAccepting(); + + /** + * Get idle time in nanoseconds, or 0 if the connection is not idle. + */ + long getIdleTimeNanos(); +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/Route.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/Route.java new file mode 100644 index 0000000000..c845e519fa --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/Route.java @@ -0,0 +1,209 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.util.Objects; +import software.amazon.smithy.java.http.client.ProxyConfiguration; +import software.amazon.smithy.java.io.uri.SmithyUri; + +/** + * A route represents a unique destination for HTTP connections. + * + *

Connections to the same route can be pooled and reused. Two routes are equal if they connect to the same + * destination via the same path (including proxy configuration). + * + *

Important: Routes are compared by value, not identity. Two Route instances with the same scheme, host, + * port, and proxy configuration are considered equal and will share connections. + */ +public final class Route { + private final String scheme; + private final String host; + private final int port; + private final ProxyConfiguration proxy; + private final int cachedHashCode; + private final String authority; + + private Route(String scheme, String host, int port, ProxyConfiguration proxy) { + if (host == null || host.isBlank()) { + throw new IllegalArgumentException("host cannot be blank or null"); + } else if (!"http".equals(scheme) && !"https".equals(scheme)) { + throw new IllegalArgumentException("Invalid scheme: " + scheme + " (must be 'http' or 'https')"); + } + + int defaultPort = "https".equals(scheme) ? 443 : 80; + if (port == -1) { + port = defaultPort; + } else if (port <= 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port: " + port + " (must be 1-65535)"); + } + + // Normalize host to lowercase for consistent equality + this.scheme = scheme; + this.host = host.toLowerCase(); + this.port = port; + this.proxy = proxy; + this.authority = (port == defaultPort) ? this.host : this.host + ":" + port; + + // Cache hashCode for fast map lookups in connection pool + int h = this.scheme.hashCode(); + h = 31 * h + this.host.hashCode(); + h = 31 * h + this.port; + h = 31 * h + (this.proxy != null ? this.proxy.hashCode() : 0); + this.cachedHashCode = h; + } + + /** + * @return the scheme ("http" or "https") + */ + public String scheme() { + return scheme; + } + + /** + * @return the target hostname (normalized to lowercase) + */ + public String host() { + return host; + } + + /** + * @return the target port + */ + public int port() { + return port; + } + + /** + * Get the authority (host:port or just host for default ports). + * + * @return the authority string + */ + public String authority() { + return authority; + } + + /** + * @return the proxy configuration, or null if direct connection + */ + public ProxyConfiguration proxy() { + return proxy; + } + + /** + * Check if this is a secure (HTTPS) route. + * + * @return true if scheme is "https" + */ + public boolean isSecure() { + return "https".equals(scheme); + } + + /** + * Check if this route goes through a proxy. + * + * @return true if proxy configuration is present + */ + public boolean usesProxy() { + return proxy != null; + } + + /** + * Create a Route from a URI without proxy. + * + *

The URI's path, query, and fragment are ignored. + * Only scheme, host, and port are used. + * + * @param uri the URI to extract route from + * @return a Route for direct connection + * @throws IllegalArgumentException if URI is invalid + */ + public static Route from(SmithyUri uri) { + return from(uri, null); + } + + /** + * Create a Route from a URI with optional proxy configuration. + * + *

The URI's path, query, and fragment are ignored. Only scheme, host, and port are used. + * + * @param uri the URI to extract route from + * @param proxy optional proxy configuration (null for direct connection) + * @return a Route for the given URI and proxy + * @throws IllegalArgumentException if URI is invalid + */ + public static Route from(SmithyUri uri, ProxyConfiguration proxy) { + return new Route(uri.getScheme(), uri.getHost(), uri.getPort(), proxy); + } + + /** + * Create a Route for direct connection (no proxy). + * + * @param scheme "http" or "https" + * @param host target hostname + * @param port target port + * @return a Route for direct connection + */ + public static Route direct(String scheme, String host, int port) { + return new Route(scheme, host, port, null); + } + + /** + * Create a Route through a proxy. + * + * @param scheme "http" or "https" + * @param host target hostname + * @param port target port + * @param proxy proxy configuration + * @return a Route for proxied connection + */ + public static Route viaProxy(String scheme, String host, int port, ProxyConfiguration proxy) { + Objects.requireNonNull(proxy, "proxy cannot be null (use direct() for no proxy)"); + return new Route(scheme, host, port, proxy); + } + + /** + * Create a new Route with a different proxy configuration. + * + * @param proxy new proxy configuration (null for direct connection) + * @return new Route with updated proxy + */ + public Route withProxy(ProxyConfiguration proxy) { + return Objects.equals(this.proxy, proxy) ? this : new Route(scheme, host, port, proxy); + } + + /** + * Create a new Route without proxy (direct connection). + * + * @return new Route with no proxy + */ + public Route withoutProxy() { + return proxy == null ? this : new Route(scheme, host, port, null); + } + + @Override + public int hashCode() { + return cachedHashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Route other)) { + return false; + } + return port == other.port + && scheme.equals(other.scheme) + && host.equals(other.host) + && Objects.equals(proxy, other.proxy); + } + + @Override + public String toString() { + return "Route[scheme=" + scheme + ", host=" + host + ", port=" + port + ", proxy=" + proxy + "]"; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SSLEngineTransport.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SSLEngineTransport.java new file mode 100644 index 0000000000..9d6234b968 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SSLEngineTransport.java @@ -0,0 +1,894 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.channel.unix.Buffer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import java.io.EOFException; +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.channels.ClosedChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; + +/** + * TLS transport using {@link SSLEngine} for ByteBuffer-based encryption/decryption. + * + *

Provides both stream-based and channel-based I/O. The channel API avoids + * intermediate byte[] copies by operating directly on ByteBuffers through the + * SSLEngine, avoiding some intermediate byte[] copies. + * + *

Thread safety: reads and writes can happen concurrently from different threads. + * The SSLEngine is protected by a lock for unwrap/wrap, but socket I/O happens + * outside the lock. + */ +final class SSLEngineTransport implements ConnectionTransport { + + private final InputStream socketIn; + private final OutputStream socketOut; + private final SSLEngine engine; + // Frees any provider-native engine resources (a no-op for the JDK engine, a ref-count release for + // a native engine such as BoringSSL/tcnative). Invoked exactly once on close, AFTER the socket is + // closed, on every close path including errors. + private final Runnable engineReleaser; + private final ReentrantLock engineLock = new ReentrantLock(); + private final Socket socket; + private final SocketChannel socketChannel; + // Experimental persistent-registration epoll socket backend. Non-null only when the epoll + // transport is enabled (Linux + Epoll.isAvailable()); when set, socket/socketIn/socketOut/ + // socketChannel/readTimer are all null and the byte-level read/write/flush/timeout/close routes + // through this channel instead of the JDK NIO SocketChannel. The TLS wrap/unwrap and all buffer + // management above this seam are identical on both backends. + private final EpollChannel epollChannel; + // Read deadline (ms) for the epoll path, mirroring SO_TIMEOUT on the NIO path. Mutated by + // setReadTimeout; 0 means no deadline. Unused on the NIO path (which uses socket.setSoTimeout). + private int epollReadTimeoutMs; + // Shared watchdog enforcing the read deadline on the blocking-channel path. Null => fall back to + // an untimed blocking read (deadline still bounded by the request-level timeout above the stack). + private final Timer readTimer; + private final ByteBuffer emptyBuffer = ByteBuffer.allocate(0); + private final byte[] singleByteRead = new byte[1]; + private final byte[] singleByteWrite = new byte[1]; + + // Network-side buffers (ciphertext). netIn is always in "write" mode (position = end of data). + private ByteBuffer netIn; + private ByteBuffer netOut; + + // Application-side read buffer (plaintext from unwrap). Always in "read" mode (position = next byte). + private ByteBuffer appIn; + private final boolean appBufferDirect; + + private volatile boolean closed; + private boolean eof; + + /** + * @param readBufferSize target capacity (bytes) for the ciphertext-read ({@code netIn}) and + * plaintext-unwrap ({@code appIn}) buffers. Sized up to at least one TLS record. A larger + * value lets one {@code socketChannel.read} pull many records that {@link #readAndUnwrap} + * then drains in a single locked pass (one {@code compact} per socket read, not per record), + * collapsing read syscalls, watchdog arms, epoll registrations, and VT park/unpark cycles + * proportionally to the records-per-read ratio. + * @param writeBufferSize target capacity (bytes) for the ciphertext-write ({@code netOut}) + * buffer. Sized up to at least one TLS record. A larger value lets {@link #write} accumulate + * several wrapped records before one {@code writeNetOut}, collapsing write syscalls (and the + * attendant VT park/unpark) for bulk uploads. + */ + SSLEngineTransport( + Socket socket, + SSLEngine engine, + Runnable engineReleaser, + Timer readTimer, + int readBufferSize, + int writeBufferSize + ) + throws IOException { + this.socket = socket; + this.socketIn = socket.getInputStream(); + this.socketOut = socket.getOutputStream(); + this.socketChannel = socket.getChannel(); + this.epollChannel = null; + this.engine = engine; + this.engineReleaser = engineReleaser != null ? engineReleaser : () -> {}; + this.readTimer = readTimer; + + // Direct buffers when we own a SocketChannel so a native engine works straight off-heap. + boolean direct = socketChannel != null; + this.appBufferDirect = direct; + allocateBuffers(direct, readBufferSize, writeBufferSize); + } + + /** + * Construct a transport whose ciphertext I/O is backed by the experimental persistent-registration + * {@link EpollChannel} instead of a JDK {@link SocketChannel}. The TLS state machine, buffer + * management, and every method above the byte-level socket seam are identical to the NIO path; only + * {@code readIntoNetIn}/{@code writeNetOut}/{@code flushSocket}/{@code setReadTimeout}/{@code close} + * route through the epoll channel. Buffers are always direct (the raw-address recv/send path + * requires it). + * + * @param epollChannel a connected epoll channel (TLS not yet started) + * @param engine the SSL engine driving TLS + * @param engineReleaser native-engine release callback, invoked once on close + * @param readTimeoutMs initial read deadline in milliseconds (0 = none); mirrors SO_TIMEOUT + * @param readBufferSize ciphertext-read / plaintext-unwrap buffer target capacity + * @param writeBufferSize ciphertext-write buffer target capacity + */ + SSLEngineTransport( + EpollChannel epollChannel, + SSLEngine engine, + Runnable engineReleaser, + int readTimeoutMs, + int readBufferSize, + int writeBufferSize + ) + throws IOException { + this.socket = null; + this.socketIn = null; + this.socketOut = null; + this.socketChannel = null; + this.epollChannel = epollChannel; + this.epollReadTimeoutMs = readTimeoutMs; + this.engine = engine; + this.engineReleaser = engineReleaser != null ? engineReleaser : () -> {}; + this.readTimer = null; + + // The raw-address recv/send path operates on the buffer's native memory address, so buffers + // must be direct. + this.appBufferDirect = true; + allocateBuffers(true, readBufferSize, writeBufferSize); + } + + // Allocate netIn/netOut/appIn sized to at least one TLS record. netIn holds buffered ciphertext; + // appIn holds the plaintext drained from it. Per TLS record plaintext < ciphertext (record framing + // + AEAD tag overhead), so sizing appIn >= netIn guarantees one drain pass empties every whole + // record netIn can hold without an appIn overflow mid-pass, keeping the trailing compact to at + // most one partial record. netOut must hold at least one whole packet; larger lets write() coalesce + // several records. + private void allocateBuffers(boolean direct, int readBufferSize, int writeBufferSize) { + SSLSession session = engine.getSession(); + int packetSize = session.getPacketBufferSize(); + int appSize = session.getApplicationBufferSize(); + + int netCap = Math.max(readBufferSize, packetSize); + int appCap = Math.max(readBufferSize, appSize); + int netOutCap = Math.max(writeBufferSize, packetSize); + + this.netIn = direct ? ByteBuffer.allocateDirect(netCap) : ByteBuffer.allocate(netCap); + this.netOut = direct ? ByteBuffer.allocateDirect(netOutCap) : ByteBuffer.allocate(netOutCap); + this.appIn = allocateAppBuffer(appCap); + this.appIn.flip(); // start empty (read mode, nothing to read) + } + + /** + * Perform the TLS handshake. Must be called before any read/write. + */ + void handshake() throws IOException { + engine.beginHandshake(); + HandshakeStatus hs = engine.getHandshakeStatus(); + + while (hs != HandshakeStatus.FINISHED && hs != HandshakeStatus.NOT_HANDSHAKING) { + switch (hs) { + case NEED_WRAP -> hs = handshakeWrap(); + case NEED_UNWRAP, NEED_UNWRAP_AGAIN -> hs = handshakeUnwrap(hs); + case NEED_TASK -> hs = runDelegatedTasks(); + default -> throw new SSLException("Unexpected handshake status: " + hs); + } + } + } + + private HandshakeStatus handshakeWrap() throws IOException { + netOut.clear(); + emptyBuffer.clear(); + SSLEngineResult result = engine.wrap(emptyBuffer, netOut); + if (result.getStatus() == Status.BUFFER_OVERFLOW) { + netOut = allocateNetBuffer(engine.getSession().getPacketBufferSize()); + return result.getHandshakeStatus(); + } + if (result.getStatus() == Status.CLOSED) { + throw new SSLException("Engine closed during handshake wrap"); + } + netOut.flip(); + if (netOut.hasRemaining()) { + writeNetOut(); + flushSocket(); + } + return result.getHandshakeStatus(); + } + + private HandshakeStatus handshakeUnwrap(HandshakeStatus current) throws IOException { + if (current == HandshakeStatus.NEED_UNWRAP && netIn.position() == 0) { + if (!readIntoNetIn()) { + throw new EOFException("Connection closed during handshake"); + } + } + + while (true) { + netIn.flip(); + appIn.clear(); + SSLEngineResult result; + engineLock.lock(); + try { + result = engine.unwrap(netIn, appIn); + } finally { + engineLock.unlock(); + } + netIn.compact(); + appIn.flip(); + + Status status = result.getStatus(); + if (status == Status.BUFFER_OVERFLOW) { + appIn = allocateAppBuffer(engine.getSession().getApplicationBufferSize()); + appIn.flip(); + continue; + } + if (status == Status.BUFFER_UNDERFLOW) { + netIn = ensureCapacity(netIn, engine.getSession().getPacketBufferSize()); + if (!readIntoNetIn()) { + throw new EOFException("Connection closed during handshake (BUFFER_UNDERFLOW)"); + } + continue; + } + if (status == Status.CLOSED) { + throw new SSLException("Engine closed during handshake unwrap"); + } + return result.getHandshakeStatus(); + } + } + + private HandshakeStatus runDelegatedTasks() { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + return engine.getHandshakeStatus(); + } + + /** + * Read from socket directly into netIn's backing array. No intermediate copy. + * + * @return true if data was read, false on EOF + */ + private boolean readIntoNetIn() throws IOException { + int space = netIn.remaining(); + if (space == 0) { + netIn = ensureCapacity(netIn, netIn.capacity() * 2); + } + int n; + if (epollChannel != null) { + // Raw-address read straight into netIn's off-heap region: recvAddress on the buffer's + // native memory address advances nothing itself, so we bump netIn's position by the + // count. The address is recomputed per call because netIn may have been reallocated by + // ensureCapacity (the recompute is a cheap Unsafe field read, still cheaper than the + // per-op GetDirectBufferAddress the ByteBuffer overload would pay). The read deadline + // mirrors SO_TIMEOUT on the NIO path. + long base = Buffer.memoryAddress(netIn); + int pos = netIn.position(); + int limit = netIn.limit(); + n = epollChannel.readAddress(base, pos, limit, epollReadTimeoutMs); + if (n > 0) { + netIn.position(pos + n); + } + } else if (socketChannel != null) { + int timeoutMs = socket.getSoTimeout(); + if (timeoutMs > 0 && readTimer != null) { + n = readWithTimeout(timeoutMs); + } else { + // No deadline (or no shared timer): a plain blocking channel read parks the calling + // virtual thread cleanly. The request-level timeout above the stack still bounds it. + n = socketChannel.read(netIn); + } + } else { + n = socketIn.read(netIn.array(), netIn.arrayOffset() + netIn.position(), netIn.remaining()); + if (n > 0) { + netIn.position(netIn.position() + n); + } + } + if (n <= 0) { + eof = true; + return false; + } + return true; + } + + /** + * Blocking-channel read with a watchdog-enforced deadline. A blocking {@link SocketChannel#read} + * ignores {@code SO_TIMEOUT}, so instead of opening an epoll {@code Selector} per read (which cost + * an {@code epoll_create1}/{@code eventfd}/{@code close} cycle and a blocking-mode flip every call) + * the read parks the virtual thread and a single shared {@link #readTimer} closes the channel if + * the deadline passes, waking the parked read with an {@code AsynchronousCloseException} that is + * surfaced as a {@link SocketTimeoutException}. The channel stays in blocking mode throughout. + */ + private int readWithTimeout(int timeoutMs) throws IOException { + Timeout watchdog = readTimer.newTimeout(t -> closeChannelQuietly(), timeoutMs, TimeUnit.MILLISECONDS); + try { + return socketChannel.read(netIn); + } catch (ClosedChannelException e) { + // The watchdog (or a concurrent close) closed the channel out from under the read + // (AsynchronousCloseException is the watchdog case; both extend ClosedChannelException). + if (watchdog.isExpired()) { + throw new SocketTimeoutException("Read timed out after " + timeoutMs + "ms"); + } + throw e; + } finally { + watchdog.cancel(); + } + } + + private void closeChannelQuietly() { + try { + socketChannel.close(); + } catch (IOException ignored) { + // best effort: the parked read will unblock with AsynchronousCloseException + } + } + + private void writeNetOut() throws IOException { + if (!netOut.hasRemaining()) { + return; + } + if (epollChannel != null) { + // writeAddress drains the whole [pos, limit) region (looping internally on partial + // sends / back-pressure), so advance netOut to its limit in one step afterward. + int pos = netOut.position(); + int limit = netOut.limit(); + epollChannel.writeAddress(Buffer.memoryAddress(netOut), pos, limit); + netOut.position(limit); + } else if (socketChannel != null) { + while (netOut.hasRemaining()) { + socketChannel.write(netOut); + } + } else { + socketOut.write(netOut.array(), netOut.arrayOffset() + netOut.position(), netOut.remaining()); + netOut.position(netOut.limit()); + } + } + + private void flushSocket() throws IOException { + // Only the stream (non-channel) backend buffers writes; both the NIO SocketChannel and the + // epoll channel write straight through, so flush is a no-op there. + if (socketChannel == null && epollChannel == null) { + socketOut.flush(); + } + } + + private ByteBuffer allocateNetBuffer(int size) { + return appBufferDirect ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size); + } + + // Allocate the plaintext unwrap-destination buffer, direct when we own a SocketChannel so a native + // engine decrypts straight into it (no temp-direct staging copy). Every appIn (re)allocation must + // route through here, or a BUFFER_OVERFLOW resize would silently revert appIn to heap. + private ByteBuffer allocateAppBuffer(int size) { + return appBufferDirect ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size); + } + + @Override + public void setReadTimeout(int timeoutMs) throws IOException { + if (epollChannel != null) { + // Mirrors SO_TIMEOUT: the next readIntoNetIn parks with this deadline (0 == infinite). + this.epollReadTimeoutMs = timeoutMs; + } else { + socket.setSoTimeout(timeoutMs); + } + } + + @Override + public int getReadTimeout() throws IOException { + return epollChannel != null ? epollReadTimeoutMs : socket.getSoTimeout(); + } + + @Override + public boolean hasBufferedData() { + return appIn.hasRemaining(); + } + + @Override + public SSLSession sslSession() { + return engine.getSession(); + } + + @Override + public String negotiatedProtocol() { + String proto = engine.getApplicationProtocol(); + return (proto != null && !proto.isEmpty()) ? proto : null; + } + + @Override + public boolean isOpen() { + return !closed; + } + + // ==================== Stream-based I/O (InputStream/OutputStream) ==================== + + /** + * Read decrypted data into the given byte array. + * + * @return bytes read, or -1 on EOF + */ + int read(byte[] b, int off, int len) throws IOException { + if (closed) { + return -1; + } + if (len == 0) { + return 0; + } + + // Fast path: data already decrypted in appIn + if (appIn.hasRemaining()) { + int toCopy = Math.min(appIn.remaining(), len); + appIn.get(b, off, toCopy); + return toCopy; + } + + return readAndUnwrap(b, off, len); + } + + private int readAndUnwrap(byte[] b, int off, int len) throws IOException { + while (true) { + if (eof && netIn.position() == 0) { + return -1; + } + + if (netIn.position() == 0) { + if (!readIntoNetIn()) { + return -1; + } + } + + netIn.flip(); + appIn.clear(); + Status status; + while (true) { + SSLEngineResult result; + engineLock.lock(); + try { + result = engine.unwrap(netIn, appIn); + } finally { + engineLock.unlock(); + } + status = result.getStatus(); + if (status == Status.OK) { + handlePostResult(result); + // No forward progress (defensive against a pathological 0/0 OK) or netIn drained + // of whole records, so stop the drain and serve what we have. + if ((result.bytesConsumed() == 0 && result.bytesProduced() == 0) || !netIn.hasRemaining()) { + break; + } + // Another whole record may be buffered; keep draining into appIn. + continue; + } + // UNDERFLOW (partial trailing record), OVERFLOW (appIn full), or CLOSED. + break; + } + netIn.compact(); + appIn.flip(); + + // Serve whatever plaintext we drained this pass. + if (appIn.hasRemaining()) { + int toCopy = Math.min(appIn.remaining(), len); + appIn.get(b, off, toCopy); + return toCopy; + } + + // No plaintext produced, so act on why the drain stopped. + switch (status) { + case BUFFER_UNDERFLOW -> { + netIn = ensureCapacity(netIn, engine.getSession().getPacketBufferSize()); + if (!readIntoNetIn()) { + if (netIn.position() == 0) { + return -1; + } + throw new EOFException("Connection closed with partial TLS record"); + } + } + case BUFFER_OVERFLOW -> { + appIn = allocateAppBuffer(engine.getSession().getApplicationBufferSize()); + appIn.flip(); + } + case CLOSED -> { + return -1; + } + default -> { + // OK but produced 0 bytes (e.g. a post-handshake message consumed no app data); + // loop to read/unwrap again. + } + } + } + } + + // ==================== Channel-based I/O (ByteBuffer path) ==================== + + /** + * Read decrypted data directly into a ByteBuffer. + * + *

Unwraps TLS data directly into the destination buffer when possible, + * avoiding the intermediate appIn buffer entirely. Falls back to appIn for + * cases where the destination buffer is too small for SSLEngine. + * + * @param dst destination buffer + * @return bytes read, or -1 on EOF + */ + int readChannel(ByteBuffer dst) throws IOException { + if (closed) { + return -1; + } else if (!dst.hasRemaining()) { + return 0; + } else if (appIn.hasRemaining()) { + // Fast path: drain any leftover plaintext from appIn + return drainAppIn(dst); + } + + return readAndUnwrapChannel(dst); + } + + private int readAndUnwrapChannel(ByteBuffer dst) throws IOException { + while (true) { + if (eof && netIn.position() == 0) { + return -1; + } else if (netIn.position() == 0 && !readIntoNetIn()) { + return -1; + } + + netIn.flip(); + + // Try to unwrap directly into dst if it's large enough for SSLEngine + int appBufSize = engine.getSession().getApplicationBufferSize(); + boolean directUnwrap = dst.remaining() >= appBufSize; + + SSLEngineResult result; + if (directUnwrap) { + // Zero-copy path: unwrap directly into caller's buffer + engineLock.lock(); + try { + result = engine.unwrap(netIn, dst); + } finally { + engineLock.unlock(); + } + netIn.compact(); + + switch (result.getStatus()) { + case OK -> { + handlePostResult(result); + if (result.bytesProduced() > 0) { + return result.bytesProduced(); + } + // No data produced (e.g., post-handshake message), loop + } + case BUFFER_UNDERFLOW -> { + netIn = ensureCapacity(netIn, engine.getSession().getPacketBufferSize()); + if (!readIntoNetIn()) { + if (netIn.position() == 0) { + return -1; + } + throw new EOFException("Connection closed with partial TLS record"); + } + } + case BUFFER_OVERFLOW -> { + // dst too small despite our check, so fall through to appIn path + directUnwrap = false; + } + case CLOSED -> { + return -1; + } + } + if (directUnwrap) { + continue; + } + // Fall through to appIn path on BUFFER_OVERFLOW + netIn.flip(); // re-flip for the appIn path below + } + + // Fallback: unwrap into appIn, then copy to dst + appIn.clear(); + engineLock.lock(); + try { + result = engine.unwrap(netIn, appIn); + } finally { + engineLock.unlock(); + } + netIn.compact(); + appIn.flip(); + + switch (result.getStatus()) { + case OK -> { + handlePostResult(result); + if (appIn.hasRemaining()) { + return drainAppIn(dst); + } + } + case BUFFER_UNDERFLOW -> { + netIn = ensureCapacity(netIn, engine.getSession().getPacketBufferSize()); + if (!readIntoNetIn()) { + if (netIn.position() == 0) { + return -1; + } + throw new EOFException("Connection closed with partial TLS record"); + } + } + case BUFFER_OVERFLOW -> { + appIn = allocateAppBuffer(appBufSize); + appIn.flip(); + } + case CLOSED -> { + return -1; + } + } + } + } + + private int drainAppIn(ByteBuffer dst) { + int toCopy = Math.min(appIn.remaining(), dst.remaining()); + int oldLimit = appIn.limit(); + appIn.limit(appIn.position() + toCopy); + dst.put(appIn); + appIn.limit(oldLimit); + return toCopy; + } + + /** + * Encrypt and write data from the given ByteBuffer. Zero-copy write path. + * + * @param src source buffer with plaintext data + * @return bytes consumed from src + */ + int writeChannel(ByteBuffer src) throws IOException { + if (closed) { + throw new IOException("Transport closed"); + } + int totalConsumed = 0; + while (src.hasRemaining()) { + netOut.clear(); + SSLEngineResult result; + engineLock.lock(); + try { + result = engine.wrap(src, netOut); + } finally { + engineLock.unlock(); + } + totalConsumed += result.bytesConsumed(); + + if (result.getStatus() == Status.BUFFER_OVERFLOW) { + netOut = allocateNetBuffer(engine.getSession().getPacketBufferSize()); + continue; + } + if (result.getStatus() == Status.CLOSED) { + throw new IOException("SSLEngine closed during write"); + } + + netOut.flip(); + if (netOut.hasRemaining()) { + writeNetOut(); + } + handlePostResult(result); + } + return totalConsumed; + } + + // ==================== Stream-based write ==================== + + void write(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Transport closed"); + } + ByteBuffer src = ByteBuffer.wrap(b, off, len); + int packetSize = engine.getSession().getPacketBufferSize(); + netOut.clear(); + while (src.hasRemaining()) { + SSLEngineResult result; + engineLock.lock(); + try { + result = engine.wrap(src, netOut); + } finally { + engineLock.unlock(); + } + + if (result.getStatus() == Status.BUFFER_OVERFLOW) { + if (netOut.position() > 0) { + flushAccumulatedNetOut(); + } else { + netOut = allocateNetBuffer(packetSize); + } + continue; + } + if (result.getStatus() == Status.CLOSED) { + throw new IOException("SSLEngine closed during write"); + } + + handlePostResult(result); + + if (netOut.remaining() < packetSize || !src.hasRemaining()) { + flushAccumulatedNetOut(); + } + } + // Flush any trailing accumulated records. + if (netOut.position() > 0) { + flushAccumulatedNetOut(); + } + } + + // Flip the accumulated ciphertext in netOut, write it all to the socket, then reset to fill mode. + private void flushAccumulatedNetOut() throws IOException { + netOut.flip(); + if (netOut.hasRemaining()) { + writeNetOut(); + } + netOut.clear(); + } + + void flush() throws IOException { + flushSocket(); + } + + private void handlePostResult(SSLEngineResult result) { + HandshakeStatus hs = result.getHandshakeStatus(); + if (hs == HandshakeStatus.NEED_TASK) { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + } + } + + // ==================== Channel adapters ==================== + + @Override + public ReadableByteChannel readableChannel() { + return new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + return readChannel(dst); + } + + @Override + public boolean isOpen() { + return !closed; + } + + @Override + public void close() throws IOException { + SSLEngineTransport.this.close(); + } + }; + } + + @Override + public WritableByteChannel writableChannel() { + return new WritableByteChannel() { + @Override + public int write(ByteBuffer src) throws IOException { + return writeChannel(src); + } + + @Override + public boolean isOpen() { + return !closed; + } + + @Override + public void close() throws IOException { + SSLEngineTransport.this.close(); + } + }; + } + + // ==================== Stream adapters ==================== + + @Override + public InputStream inputStream() { + return new TransportInputStream(); + } + + @Override + public OutputStream outputStream() { + return new TransportOutputStream(); + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + closed = true; + try { + engineLock.lock(); + try { + engine.closeOutbound(); + netOut.clear(); + emptyBuffer.clear(); + engine.wrap(emptyBuffer, netOut); + netOut.flip(); + if (netOut.hasRemaining()) { + writeNetOut(); + flushSocket(); + } + } finally { + engineLock.unlock(); + } + } catch (IOException ignored) { + // Best-effort close_notify + } finally { + try { + if (epollChannel != null) { + epollChannel.close(); + } else { + socket.close(); + } + } finally { + // Release provider-native engine resources last, on every close path. For a + // reference-counted native engine (BoringSSL/tcnative) this frees off-heap memory; + // for the JDK engine it is a no-op. Must run even if close_notify or socket.close() + // threw, or a native engine leaks per connection. + engineReleaser.run(); + } + } + } + + private static ByteBuffer ensureCapacity(ByteBuffer buf, int minCapacity) { + if (buf.capacity() >= minCapacity) { + return buf; + } + ByteBuffer newBuf = buf.isDirect() + ? ByteBuffer.allocateDirect(minCapacity) + : ByteBuffer.allocate(minCapacity); + buf.flip(); + newBuf.put(buf); + return newBuf; + } + + private final class TransportInputStream extends InputStream { + @Override + public int read() throws IOException { + int n = SSLEngineTransport.this.read(singleByteRead, 0, 1); + return n < 0 ? -1 : singleByteRead[0] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return SSLEngineTransport.this.read(b, off, len); + } + + @Override + public void close() throws IOException { + SSLEngineTransport.this.close(); + } + } + + private final class TransportOutputStream extends OutputStream { + @Override + public void write(int b) throws IOException { + singleByteWrite[0] = (byte) b; + SSLEngineTransport.this.write(singleByteWrite, 0, 1); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + SSLEngineTransport.this.write(b, off, len); + } + + @Override + public void flush() throws IOException { + SSLEngineTransport.this.flush(); + } + + @Override + public void close() throws IOException { + SSLEngineTransport.this.close(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SocketTransport.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SocketTransport.java new file mode 100644 index 0000000000..e9a8ad641b --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SocketTransport.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +/** + * Transport backed by a plain {@link Socket} or {@link SSLSocket}. + */ +record SocketTransport(Socket socket) implements ConnectionTransport { + @Override + public InputStream inputStream() throws IOException { + return socket.getInputStream(); + } + + @Override + public OutputStream outputStream() throws IOException { + return socket.getOutputStream(); + } + + @Override + public ReadableByteChannel readableChannel() throws IOException { + var ch = socket.getChannel(); + if (ch != null) { + return ch; + } + return Channels.newChannel(socket.getInputStream()); + } + + @Override + public WritableByteChannel writableChannel() throws IOException { + var ch = socket.getChannel(); + if (ch != null) { + return ch; + } + return Channels.newChannel(socket.getOutputStream()); + } + + @Override + public SSLSession sslSession() { + if (socket instanceof SSLSocket ssl) { + return ssl.getSession(); + } + return null; + } + + @Override + public String negotiatedProtocol() { + if (socket instanceof SSLSocket ssl) { + String proto = ssl.getApplicationProtocol(); + return (proto != null && !proto.isEmpty()) ? proto : null; + } + return null; + } + + @Override + public boolean isOpen() { + return !socket.isClosed(); + } + + @Override + public void setReadTimeout(int timeoutMs) throws IOException { + socket.setSoTimeout(timeoutMs); + } + + @Override + public int getReadTimeout() throws IOException { + return socket.getSoTimeout(); + } + + @Override + public void close() throws IOException { + socket.close(); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SslEngineTransports.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SslEngineTransports.java new file mode 100644 index 0000000000..449cbeda94 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/SslEngineTransports.java @@ -0,0 +1,117 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.net.Socket; +import javax.net.ssl.SSLEngine; + +/** + * Builds the built-in {@link ConnectionTransport} that drives a {@code javax.net.ssl.SSLEngine}. + * + *

This is the helper a {@link TlsProvider} uses when its TLS is engine-based: the provider mints a + * client-mode {@link SSLEngine} (JDK, BoringSSL via netty-tcnative, …) and hands it here, and this + * performs the connect-time dance: select the epoll vs. socket I/O backend, apply the negotiation + * deadline, run the handshake, and release the engine on any failure. The underlying transport type is + * internal to this module; providers in other modules reach it only through this entry point. + */ +public final class SslEngineTransports { + + private SslEngineTransports() {} + + /** + * Wrap {@code engine} in a transport over the connection in {@code context}, perform the TLS + * handshake, and return the ready transport. + * + *

On success the returned transport owns both the engine and the underlying socket/channel, and + * frees them on {@link ConnectionTransport#close()}. On failure this invokes {@code releaser} and + * closes the socket/channel before throwing, so the caller need not clean up. + * + * @param context the connected endpoint plus negotiation parameters + * @param engine a configured client-mode SSL engine (client mode, endpoint id, ALPN already set) + * @param releaser frees engine-native resources; invoked exactly once on close or on failure. May + * be null when there is nothing to release (e.g. the JDK engine). + * @return a handshaken transport + * @throws IOException if the handshake fails + */ + public static ConnectionTransport connect(TlsConnectionContext context, SSLEngine engine, Runnable releaser) + throws IOException { + Runnable release = releaser != null ? releaser : () -> {}; + if (context.epollChannel() != null) { + return connectEpoll(context, engine, release); + } + return connectSocket(context, engine, release); + } + + private static ConnectionTransport connectEpoll(TlsConnectionContext context, SSLEngine engine, Runnable releaser) + throws IOException { + EpollChannel channel = context.epollChannel(); + try { + // The negotiation deadline is honored by SSLEngineTransport's own timed-park read path + // (epoll has no SO_TIMEOUT), then reset to the steady-state read timeout for requests. + SSLEngineTransport transport = new SSLEngineTransport( + channel, + engine, + releaser, + context.negotiationTimeoutMillis(), + context.tlsReadBufferSize(), + context.tlsWriteBufferSize()); + transport.handshake(); + transport.setReadTimeout(context.readTimeoutMillis()); + return transport; + } catch (IOException e) { + releaser.run(); + channel.close(); + throw new IOException("TLS handshake failed for " + context.host(), e); + } catch (RuntimeException e) { + releaser.run(); + channel.close(); + throw e; + } + } + + private static ConnectionTransport connectSocket(TlsConnectionContext context, SSLEngine engine, Runnable releaser) + throws IOException { + Socket socket = context.socket(); + try { + int originalTimeout = socket.getSoTimeout(); + socket.setSoTimeout(context.negotiationTimeoutMillis()); + try { + SSLEngineTransport transport = new SSLEngineTransport( + socket, + engine, + releaser, + context.readTimer(), + context.tlsReadBufferSize(), + context.tlsWriteBufferSize()); + transport.handshake(); + return transport; + } finally { + socket.setSoTimeout(originalTimeout); + } + } catch (IOException e) { + // Handshake/setup failed before SSLEngineTransport took ownership of the engine; release + // any native engine resources here so they don't leak on the error path. + releaser.run(); + closeQuietly(socket); + throw new IOException("TLS handshake failed for " + context.host(), e); + } catch (RuntimeException e) { + releaser.run(); + closeQuietly(socket); + throw e; + } + } + + private static void closeQuietly(Socket socket) { + try { + if (socket != null) { + socket.close(); + } + } catch (IOException ignored) { + // ignored + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsConnectionContext.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsConnectionContext.java new file mode 100644 index 0000000000..b1e6df2c2b --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsConnectionContext.java @@ -0,0 +1,177 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import io.netty.util.Timer; +import java.net.Socket; +import java.util.List; + +/** + * The inputs a {@link TlsProvider} needs to establish a TLS connection: the connected (plaintext) + * endpoint plus negotiation parameters. + * + *

New inputs are added as fields here rather than as parameters on {@link TlsProvider#connect}, + * so the provider contract stays stable as the client evolves. + * + *

Exactly one transport substrate is present. For the common path that is a connected + * {@link #socket()}. The experimental epoll backend is carried internally and is not exposed to + * out-of-module providers. + */ +public final class TlsConnectionContext { + + private final String host; + private final int port; + private final List alpnProtocols; + private final int negotiationTimeoutMillis; + private final int readTimeoutMillis; + private final int tlsReadBufferSize; + private final int tlsWriteBufferSize; + + // Exactly one of these is non-null. socket is the public substrate; epollChannel is the internal + // (Linux-only) backend, kept package-private so out-of-module providers only see the socket path. + private final Socket socket; + private final EpollChannel epollChannel; + private final Timer readTimer; + + private TlsConnectionContext(Builder b) { + this.host = b.host; + this.port = b.port; + this.alpnProtocols = b.alpnProtocols == null ? List.of() : List.copyOf(b.alpnProtocols); + this.negotiationTimeoutMillis = b.negotiationTimeoutMillis; + this.readTimeoutMillis = b.readTimeoutMillis; + this.tlsReadBufferSize = b.tlsReadBufferSize; + this.tlsWriteBufferSize = b.tlsWriteBufferSize; + this.socket = b.socket; + this.epollChannel = b.epollChannel; + this.readTimer = b.readTimer; + } + + /** Peer host, for SNI and endpoint identification. */ + public String host() { + return host; + } + + /** Peer port. */ + public int port() { + return port; + } + + /** ALPN protocols to advertise (e.g. {@code ["h2", "http/1.1"]}); never null, possibly empty. */ + public List alpnProtocols() { + return alpnProtocols; + } + + /** Handshake deadline in milliseconds; 0 means none. */ + public int negotiationTimeoutMillis() { + return negotiationTimeoutMillis; + } + + /** Steady-state read timeout in milliseconds to apply after the handshake; 0 means none. */ + public int readTimeoutMillis() { + return readTimeoutMillis; + } + + /** Target capacity for the ciphertext-read / plaintext-unwrap buffers. */ + public int tlsReadBufferSize() { + return tlsReadBufferSize; + } + + /** Target capacity for the ciphertext-write buffer. */ + public int tlsWriteBufferSize() { + return tlsWriteBufferSize; + } + + /** + * The connected plaintext socket, or null when this request uses the internal epoll backend. + * Out-of-module providers always receive a socket. + * + * @return the connected socket, or null + */ + public Socket socket() { + return socket; + } + + // ----- internal accessors for the in-module epoll backend ----- + + EpollChannel epollChannel() { + return epollChannel; + } + + Timer readTimer() { + return readTimer; + } + + static Builder builder() { + return new Builder(); + } + + static final class Builder { + private String host; + private int port; + private List alpnProtocols; + private int negotiationTimeoutMillis; + private int readTimeoutMillis; + private int tlsReadBufferSize; + private int tlsWriteBufferSize; + private Socket socket; + private EpollChannel epollChannel; + private Timer readTimer; + + Builder host(String host) { + this.host = host; + return this; + } + + Builder port(int port) { + this.port = port; + return this; + } + + Builder alpnProtocols(List alpnProtocols) { + this.alpnProtocols = alpnProtocols; + return this; + } + + Builder negotiationTimeoutMillis(int millis) { + this.negotiationTimeoutMillis = millis; + return this; + } + + Builder readTimeoutMillis(int millis) { + this.readTimeoutMillis = millis; + return this; + } + + Builder tlsReadBufferSize(int size) { + this.tlsReadBufferSize = size; + return this; + } + + Builder tlsWriteBufferSize(int size) { + this.tlsWriteBufferSize = size; + return this; + } + + Builder socket(Socket socket) { + this.socket = socket; + return this; + } + + Builder epollChannel(EpollChannel epollChannel) { + this.epollChannel = epollChannel; + return this; + } + + Builder readTimer(Timer readTimer) { + this.readTimer = readTimer; + return this; + } + + TlsConnectionContext build() { + return new TlsConnectionContext(this); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsProvider.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsProvider.java new file mode 100644 index 0000000000..26bb743a43 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/connection/TlsProvider.java @@ -0,0 +1,153 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +/** + * Pluggable TLS provider: turns a freshly connected (plaintext) socket into a handshaken, + * ready-to-use {@link ConnectionTransport}. + * + *

This is the provider-neutral seam for selecting a TLS implementation. A provider need not be based + * on a {@code javax.net.ssl.SSLEngine}: one that performs TLS some other way (for example a native + * stack that does its own socket I/O, or a QUIC stack with integrated TLS 1.3 for a future HTTP/3 + * transport) simply returns its own {@code ConnectionTransport}. Engine-based providers (the built-in + * JDK provider, BoringSSL) build the standard transport via {@link SslEngineTransports}; an out-of-module + * provider may return any {@code ConnectionTransport}. + * + *

The provider owns the handshake: {@link #connect} returns only after TLS negotiation has + * succeeded, and the returned transport is positioned for application I/O. On failure the provider + * must release any resources it allocated (including the supplied socket/channel) before throwing. + * + *

Discovery (opt-in)

+ * Providers may be registered for {@link ServiceLoader} (e.g. the BoringSSL module ships a + * {@code META-INF/services} entry). Discovery is opt-in: a registered provider is engaged only + * when the system property {@value #PROVIDER_PROPERTY} names its fully-qualified class name. Merely + * having a provider on the classpath changes nothing (the built-in JDK provider remains the default), + * and an explicit {@code HttpClient.Builder.tlsProvider(...)} always takes precedence over the property. + */ +@FunctionalInterface +public interface TlsProvider { + + /** + * System property selecting a discovered provider by fully-qualified class name, e.g. + * {@code -Dsmithy-java.tls-provider=software.amazon.smithy.java.client.http.boringssl.BoringSslTlsProvider}. + */ + String PROVIDER_PROPERTY = "smithy-java.tls-provider"; + + /** + * Perform the TLS handshake over the connection described by {@code connection} and return a + * handshaken transport. + * + *

The provider takes ownership of the connection's underlying socket/channel: on success the + * returned transport owns it (and frees it on {@link ConnectionTransport#close()}); on failure the + * provider releases it before throwing. + * + * @param connection the connected (plaintext) endpoint plus negotiation parameters + * @return a handshaken transport ready for application reads/writes + * @throws IOException if the connection or handshake fails + */ + ConnectionTransport connect(TlsConnectionContext connection) throws IOException; + + /** + * Whether this provider is usable in the current runtime. A provider backed by a native library + * that failed to load should report {@code false} so callers can fall back to the JDK provider. + * + * @return true if the provider can establish connections + */ + default boolean isAvailable() { + return true; + } + + /** + * Whether this provider can drive a connection over the client's internal epoll transport. + * + *

The epoll backend hands the provider a {@link TlsConnectionContext} whose + * {@link TlsConnectionContext#socket()} is {@code null}; the underlying byte channel is internal and + * is consumable only through {@link SslEngineTransports} (i.e. by engine-based providers). A provider + * that does its own socket I/O therefore needs a real {@code socket()} and must return {@code false} + * (the default), so the client uses the NIO socket path for it. Built-in engine-based providers + * (JDK, BoringSSL) return {@code true} since they delegate to {@code SslEngineTransports}. + * + * @return true if the provider supports the internal epoll transport (and thus a null {@code socket()}) + */ + default boolean supportsEpoll() { + return false; + } + + /** + * Resolve the provider selected by {@value #PROVIDER_PROPERTY}, if set. + * + *

When the property is set, the {@link ServiceLoader}-discovered provider whose class has the + * named fully-qualified name is returned, provided it is {@link #isAvailable() available}. Returns + * null when the property is unset (the caller should use its default, typically the JDK provider). + * + * @return the selected provider, or null if the property is unset + * @throws IllegalStateException if the property names a provider that is not discoverable, or is + * discovered but reports unavailable + */ + static TlsProvider fromSystemProperty() { + String fqcn = System.getProperty(PROVIDER_PROPERTY); + if (fqcn == null || fqcn.isBlank()) { + return null; + } + // Pass null so byClassName uses TlsProvider's own loader (plus the thread-context loader as a + // fallback). The interface's loader always sees a provider on the module path, including under + // GraalVM native-image where the thread-context loader can be null. + return byClassName(fqcn.trim(), null); + } + + /** + * Find the {@link ServiceLoader}-registered {@code TlsProvider} whose class has the given + * fully-qualified name and is available. + * + *

Discovery is by {@link ServiceLoader} only (never reflective {@code Class.forName}), so it is + * GraalVM native-image safe: registered providers are matched by their already-loaded class name. + * Both this interface's class loader and the thread-context loader (when distinct and non-null) are + * searched, so the lookup works whether or not a context loader is set. + * + * @param fqcn fully-qualified class name of the desired provider + * @param classLoader class loader to discover services with; when null, this interface's loader is + * used + * @return the matching, available provider + * @throws IllegalStateException if no such provider is registered, or it is unavailable + */ + static TlsProvider byClassName(String fqcn, ClassLoader classLoader) { + ClassLoader primary = classLoader != null ? classLoader : TlsProvider.class.getClassLoader(); + ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); + + List discovered = new ArrayList<>(); + TlsProvider match = findIn(primary, fqcn, discovered); + if (match == null && contextLoader != null && contextLoader != primary) { + match = findIn(contextLoader, fqcn, discovered); + } + if (match == null) { + throw new IllegalStateException( + "No TLS provider registered with class name '" + fqcn + "' (from " + PROVIDER_PROPERTY + + "). Discovered providers: " + discovered); + } + if (!match.isAvailable()) { + throw new IllegalStateException( + "TLS provider '" + fqcn + "' (from " + PROVIDER_PROPERTY + ") is registered but reports " + + "unavailable in this runtime (e.g. its native library failed to load)."); + } + return match; + } + + private static TlsProvider findIn(ClassLoader loader, String fqcn, List discovered) { + for (TlsProvider provider : ServiceLoader.load(TlsProvider.class, loader)) { + String name = provider.getClass().getName(); + discovered.add(name); + if (name.equals(fqcn)) { + return provider; + } + } + return null; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/DnsResolver.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/DnsResolver.java new file mode 100644 index 0000000000..0a374d0326 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/DnsResolver.java @@ -0,0 +1,133 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.List; +import java.util.Map; + +/** + * A blocking DNS resolver used to resolve hostnames to IP addresses. + * + *

Thread-safe: All implementations must be safe for concurrent use. + */ +public interface DnsResolver { + // Design note: we return all addresses and not just one because it allows for algorithms like happy eyeballs to + // race connections across IPs. + + /** + * Resolves a hostname to IP addresses. + * + *

Returns all available addresses in preference order, typically with IPv6 + * addresses before IPv4 as determined by the system's address selection policy + * (RFC 6724). + * + *

Implementations may: + *

    + *
  • Rotate addresses across calls for load distribution
  • + *
  • Cache results with appropriate TTL
  • + *
  • Exclude recently failed addresses
  • + *
+ * + *

This method may block for DNS lookup. + * + * @param hostname the hostname to resolve (e.g., "api.example.com") + * @return unmodifiable list of resolved IP addresses, never null or empty + * @throws IOException if DNS resolution fails and no cached addresses are available + */ + List resolve(String hostname) throws IOException; + + /** + * Reports that a connection attempt to an address failed. + * + *

Implementations may use this to temporarily deprioritize or exclude the + * address from future results until it likely recovers. + * + *

Default: No-op. Stateless resolvers ignore failure reports. + * + * @param address the IP address that failed to connect + */ + default void reportFailure(InetAddress address) { + // nothing by default + } + + /** + * Purges cached entries for a specific hostname. + * + *

Forces a fresh DNS lookup on the next {@link #resolve} call for this hostname. + * + *

Default: No-op. Stateless resolvers have no cache. + * + * @param hostname the hostname to purge from cache + */ + default void purgeCache(String hostname) {} + + /** + * Purges all cached entries. + * + *

Forces fresh DNS lookups for all hostnames. + * + *

Default: No-op. Stateless resolvers have no cache. + */ + default void purgeCache() {} + + /** + * Creates a DNS resolver using the JVM's default resolution. + * + *

Delegates to {@link InetAddress#getAllByName(String)}, which respects + * JVM DNS cache settings configured via security properties: + *

    + *
  • {@code networkaddress.cache.ttl} - seconds to cache successful lookups (default: 30)
  • + *
  • {@code networkaddress.cache.negative.ttl} - seconds to cache failures (default: 10)
  • + *
+ * + *

This resolver is stateless and does not track failures or perform rotation. + * + * @return system DNS resolver singleton + */ + static DnsResolver system() { + return SystemDnsResolver.INSTANCE; + } + + /** + * Creates a DNS resolver that rotates the system resolver's results across calls. + * + * @return a round-robin DNS resolver backed by the system resolver. + */ + static DnsResolver roundRobin() { + return roundRobin(system()); + } + + /** + * Decorates a DNS resolver so that multi-address results are rotated across calls. + * + *

This preserves each resolved address set but changes the first address on subsequent calls. Connection + * factories that try addresses in returned order will spread new connections across multi-answer DNS records while + * still retaining failover to the remaining addresses. + * + * @param resolver resolver to decorate. + * @return a round-robin DNS resolver. + * @throws NullPointerException if resolver is null. + */ + static DnsResolver roundRobin(DnsResolver resolver) { + return new RoundRobinDnsResolver(resolver); + } + + /** + * Creates a DNS resolver with static hostname mappings. + * + *

Returns pre-configured addresses without performing DNS queries. + * Useful for testing and local development. + * + * @param mappings hostname to address list mappings + * @return static DNS resolver + * @throws NullPointerException if mappings is null + */ + static DnsResolver staticMapping(Map> mappings) { + return new StaticDnsResolver(mappings); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolver.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolver.java new file mode 100644 index 0000000000..ec85a920aa --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolver.java @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.AbstractList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.RandomAccess; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * DNS resolver decorator that rotates multi-address results per hostname. + */ +final class RoundRobinDnsResolver implements DnsResolver { + private final DnsResolver delegate; + private final ConcurrentMap offsets = new ConcurrentHashMap<>(); + + RoundRobinDnsResolver(DnsResolver delegate) { + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + } + + @Override + public List resolve(String hostname) throws IOException { + List addresses = delegate.resolve(hostname); + int size = addresses.size(); + if (size <= 1) { + return addresses; + } + + int offset = Math.floorMod( + offsets.computeIfAbsent(normalize(hostname), ignored -> new AtomicInteger()).getAndIncrement(), + size); + if (offset == 0) { + return addresses; + } + + return new RotatedAddresses(addresses, offset); + } + + @Override + public void reportFailure(InetAddress address) { + delegate.reportFailure(address); + } + + @Override + public void purgeCache(String hostname) { + offsets.remove(normalize(hostname)); + delegate.purgeCache(hostname); + } + + @Override + public void purgeCache() { + offsets.clear(); + delegate.purgeCache(); + } + + private static String normalize(String hostname) { + return hostname.toLowerCase(Locale.ROOT); + } + + private static final class RotatedAddresses extends AbstractList implements RandomAccess { + private final List addresses; + private final int offset; + + RotatedAddresses(List addresses, int offset) { + this.addresses = addresses; + this.offset = offset; + } + + @Override + public InetAddress get(int index) { + Objects.checkIndex(index, addresses.size()); + return addresses.get((offset + index) % addresses.size()); + } + + @Override + public int size() { + return addresses.size(); + } + } + + @Override + public String toString() { + return "RoundRobinDnsResolver(" + delegate + ")"; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolver.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolver.java new file mode 100644 index 0000000000..3e6696d24e --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolver.java @@ -0,0 +1,48 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * DNS resolver with static hostname-to-IP mappings. + * + *

{@snippet : + * var resolver = new StaticDnsResolver(Map.of( + * "api.example.com", List.of( + * InetAddress.getByName("192.168.1.100"), + * InetAddress.getByName("192.168.1.101") + * ), + * "localhost", List.of(InetAddress.getLoopbackAddress()) + * )); + * } + */ +record StaticDnsResolver(Map> mappings) implements DnsResolver { + StaticDnsResolver(Map> mappings) { + Map> copy = new HashMap<>(mappings.size()); + for (Map.Entry> entry : mappings.entrySet()) { + List value = entry.getValue(); + if (value != null && !value.isEmpty()) { + copy.put(entry.getKey().toLowerCase(Locale.ROOT), List.copyOf(value)); + } + } + this.mappings = Map.copyOf(copy); + } + + @Override + public List resolve(String hostname) throws IOException { + List addresses = mappings.get(hostname.toLowerCase(Locale.ROOT)); + if (addresses == null) { + throw new IOException("No static mapping defined for hostname: " + hostname); + } + return addresses; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolver.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolver.java new file mode 100644 index 0000000000..fb0f2f0a50 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolver.java @@ -0,0 +1,39 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +/** + * DNS resolver using the JVM's default resolution mechanism. + */ +final class SystemDnsResolver implements DnsResolver { + + static final SystemDnsResolver INSTANCE = new SystemDnsResolver(); + + private SystemDnsResolver() {} + + @Override + public List resolve(String hostname) throws IOException { + try { + InetAddress[] addresses = InetAddress.getAllByName(hostname); + if (addresses.length == 0) { + throw new IOException("DNS resolution returned no addresses for: " + hostname); + } + return List.of(addresses); + } catch (UnknownHostException e) { + throw new IOException("Failed to resolve hostname: " + hostname, e); + } + } + + @Override + public String toString() { + return "SystemDnsResolver"; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStream.java new file mode 100644 index 0000000000..8bf8843a0c --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStream.java @@ -0,0 +1,339 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.ModifiableHttpHeaders; + +/** + * InputStream that reads HTTP/1.1 chunked transfer encoding format (RFC 9112). + * + *

ChunkedInputStream intentionally doesn't close the delegate stream. The connection lifecycle is managed by + * H1Connection, which is managed by the pool. + */ +final class ChunkedInputStream extends InputStream { + private static final long MAX_CHUNK_SIZE = readMaxChunkSize(); + private static final long DEFAULT_MAX_CHUNK_SIZE = 1024 * 1024; // 1 MB + private static final int MAX_LINE_LENGTH = 8192; + + private final UnsyncBufferedInputStream delegate; + private final H1Exchange exchange; + private long chunkRemaining = -1; // -1 means need to read chunk size + private boolean eof; + private boolean closed; + private final byte[] lineBuffer; + private HttpHeaders trailers; // Trailer headers parsed from final chunk. + + ChunkedInputStream(UnsyncBufferedInputStream delegate) { + this(delegate, null, new byte[MAX_LINE_LENGTH]); + } + + ChunkedInputStream(UnsyncBufferedInputStream delegate, H1Exchange exchange, byte[] lineBuffer) { + if (lineBuffer.length < MAX_LINE_LENGTH) { + throw new IllegalArgumentException("lineBuffer must be at least " + MAX_LINE_LENGTH + " bytes"); + } + this.delegate = delegate; + this.exchange = exchange; + this.lineBuffer = lineBuffer; + } + + private static long readMaxChunkSize() { + String property = System.getProperty("smithy.http.client.maxChunkSize"); + if (property == null) { + return DEFAULT_MAX_CHUNK_SIZE; + } + try { + long size = Long.parseLong(property); + if (size <= 0) { + throw new IllegalArgumentException("smithy.http.client.maxChunkSize must be positive: " + size); + } + return size; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid smithy.http.client.maxChunkSize: " + property, e); + } + } + + @Override + public int read() throws IOException { + if (closed || eof) { + return -1; + } + + // Need to read next chunk? + if (chunkRemaining == -1 || chunkRemaining == 0) { + if (!readNextChunk()) { + return -1; // EOF + } + } + + // Read one byte from current chunk + int b = delegate.read(); + if (b != -1) { + chunkRemaining--; + } else { + throw new IOException("Unexpected end of stream in chunked encoding"); + } + + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (closed || eof) { + return -1; + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + // Need to read next chunk? + if (chunkRemaining == -1 || chunkRemaining == 0) { + if (!readNextChunk()) { + return -1; // EOF + } + } + + // Read at most chunkRemaining bytes + int toRead = (int) Math.min(len, chunkRemaining); + int n = delegate.read(b, off, toRead); + + if (n > 0) { + chunkRemaining -= n; + } else if (n == -1) { + throw new IOException("Unexpected end of stream in chunked encoding"); + } + + return n; + } + + @Override + public long skip(long n) throws IOException { + if (closed || eof || n <= 0) { + return 0; + } + + long remaining = n; + + while (remaining > 0) { + if (chunkRemaining == -1 || chunkRemaining == 0) { + if (!readNextChunk()) { + break; + } + } + + long toDiscard = Math.min(remaining, chunkRemaining); + delegate.discard(toDiscard); + chunkRemaining -= toDiscard; + remaining -= toDiscard; + } + + return n - remaining; + } + + @Override + public long transferTo(OutputStream out) throws IOException { + if (closed || eof) { + return 0; + } + + byte[] buffer = delegate.buffer(); + long transferred = 0; + + while (!eof) { + if (chunkRemaining == -1 || chunkRemaining == 0) { + if (!readNextChunk()) { + break; + } + } + + int toRead = (int) Math.min(buffer.length, chunkRemaining); + int bytesRead = read(buffer, 0, toRead); + if (bytesRead < 0) { + break; + } + out.write(buffer, 0, bytesRead); + transferred += bytesRead; + } + + return transferred; + } + + @Override + public int available() throws IOException { + if (closed || eof) { + return 0; + } + + if (chunkRemaining > 0) { + // We know up to chunkRemaining bytes remain in this chunk; cap by delegate.available(). + int available = delegate.available(); + return (int) Math.min(available, chunkRemaining); + } + + return 0; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + + // Drain remaining chunks to allow connection reuse (before setting closed flag) + if (!eof) { + transferTo(OutputStream.nullOutputStream()); + } + + closed = true; + responseBodyComplete(); + // Do not close the delegate; connection lifecycle is handled by the exchange/pool. + } + + /** + * Read the next chunk header and update state. + * + * @return true if there's more data, false if final chunk (size 0) + * @throws IOException if chunk format is invalid + */ + private boolean readNextChunk() throws IOException { + // If we just finished a chunk, consume trailing CRLF + if (chunkRemaining == 0) { + readCRLF(); + } + + // Read chunk size line directly into buffer + int lineLen = delegate.readLine(lineBuffer, MAX_LINE_LENGTH); + + long chunkSize = getChunkSize(lineLen); + + if (chunkSize > MAX_CHUNK_SIZE) { + throw new IOException("Chunk size " + chunkSize + " exceeds maximum allowed size of " + MAX_CHUNK_SIZE); + } + + if (chunkSize == 0) { + // Final chunk - read optional trailers + readTrailers(); + eof = true; + chunkRemaining = 0; + responseBodyComplete(); + return false; + } + + chunkRemaining = chunkSize; + return true; + } + + private long getChunkSize(int lineLen) throws IOException { + if (lineLen <= 0) { + throw new IOException("Empty chunk size line"); + } + + // Find end of hex size (stop at semicolon for chunk extensions, or end of line) + int sizeEnd = lineLen; + for (int i = 0; i < lineLen; i++) { + byte b = lineBuffer[i]; + if (b == ';' || b == ' ') { + sizeEnd = i; + break; + } + } + + if (sizeEnd == 0) { + throw new IOException("Missing chunk size"); + } + + // Parse hex directly from bytes + long chunkSize = parseHex(lineBuffer, 0, sizeEnd); + if (chunkSize < 0) { + throw new IOException("Negative chunk size: " + chunkSize); + } + return chunkSize; + } + + private static long parseHex(byte[] buf, int start, int end) throws IOException { + long value = 0; + for (int i = start; i < end; i++) { + byte b = buf[i]; + int digit; + if (b >= '0' && b <= '9') { + digit = b - '0'; + } else if (b >= 'a' && b <= 'f') { + digit = 10 + (b - 'a'); + } else if (b >= 'A' && b <= 'F') { + digit = 10 + (b - 'A'); + } else { + throw new IOException("Invalid hex character in chunk size: " + (char) b); + } + // Check for overflow before shifting (top 4 bits must be clear) + if ((value & 0xF000_0000_0000_0000L) != 0) { + throw new IOException("HTTP/1.1 chunk size overflow"); + } + value = (value << 4) | digit; + } + return value; + } + + /** + * Read and parse trailer headers after final chunk. + * + *

Trailers are formatted like HTTP headers and are read until a blank line. + * Parsed trailers are stored and can be retrieved via {@link #getTrailers()}. + */ + private void readTrailers() throws IOException { + ModifiableHttpHeaders parsedTrailers = HttpHeaders.ofModifiable(); + int len; + try { + while ((len = delegate.readLine(lineBuffer, MAX_LINE_LENGTH)) > 0) { + String name = H1Utils.parseHeaderLine(lineBuffer, len, parsedTrailers); + if (name == null) { + throw new IOException("Invalid trailer line: " + + new String(lineBuffer, 0, len, StandardCharsets.US_ASCII)); + } + } + } catch (IllegalArgumentException e) { + throw new IOException("Invalid trailer header", e); + } + + // Only store if we actually got trailers + if (!parsedTrailers.isEmpty()) { + this.trailers = parsedTrailers; + } + } + + /** + * Get trailer headers parsed from the chunked stream. + * + *

Trailers are only available after the stream has been fully read (EOF reached). + * Before EOF, this method returns null. + * + * @return trailer headers, or null if no trailers were received or stream not fully read + */ + HttpHeaders getTrailers() { + return trailers; + } + + private void responseBodyComplete() throws IOException { + if (exchange != null) { + exchange.responseBodyClosed(); + } + } + + private void readCRLF() throws IOException { + int cr = delegate.read(); + int lf = delegate.read(); + if (cr == -1 || lf == -1) { + throw new IOException("Unexpected end of stream: expected CRLF after chunk data"); + } + if (cr != '\r' || lf != '\n') { + throw new IOException(String.format("Expected CRLF after chunk data, got 0x%02X 0x%02X", cr, lf)); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStream.java new file mode 100644 index 0000000000..52a0ca136f --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStream.java @@ -0,0 +1,205 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.util.Objects; +import software.amazon.smithy.java.http.api.HttpHeaders; + +/** + * OutputStream that writes HTTP/1.1 chunked transfer encoding format (RFC 9112). + * + *

This stream does not close the delegate on close. The connection lifecycle is managed by {@link H1Connection}. + */ +final class ChunkedOutputStream extends OutputStream { + private final UnsyncBufferedOutputStream delegate; + private final byte[] buffer; + private int bufferPos = 0; + private boolean closed = false; + private HttpHeaders trailers; + + // Default chunk size: 8KB + static final int DEFAULT_CHUNK_SIZE = 8192; + + /** + * Create a ChunkedOutputStream with default chunk size (8KB). + */ + ChunkedOutputStream(UnsyncBufferedOutputStream delegate) { + this(delegate, DEFAULT_CHUNK_SIZE); + } + + /** + * Create a ChunkedOutputStream with specified chunk size. + * + * @param delegate underlying buffered stream to write chunks to + * @param chunkSize maximum size of each chunk in bytes (must be > 0) + */ + ChunkedOutputStream(UnsyncBufferedOutputStream delegate, int chunkSize) { + if (delegate == null) { + throw new NullPointerException("delegate"); + } else if (chunkSize <= 0) { + throw new IllegalArgumentException("chunkSize must be positive: " + chunkSize); + } + + this.delegate = delegate; + this.buffer = new byte[chunkSize]; + } + + ChunkedOutputStream(UnsyncBufferedOutputStream delegate, byte[] buffer) { + this.delegate = Objects.requireNonNull(delegate, "delegate"); + this.buffer = Objects.requireNonNull(buffer, "buffer"); + if (buffer.length == 0) { + throw new IllegalArgumentException("buffer must not be empty"); + } + } + + /** + * Set trailer headers to be sent after the final chunk. + * + *

Must be called before {@link #close()}. + * + * @param trailers the trailer headers to send + */ + void setTrailers(HttpHeaders trailers) { + this.trailers = trailers; + } + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + + buffer[bufferPos++] = (byte) b; + + if (bufferPos >= buffer.length) { + flushChunk(); + } + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + int remaining = len; + int offset = off; + + while (remaining > 0) { + if (bufferPos == 0 && remaining >= buffer.length) { + writeChunk(b, offset, buffer.length); + offset += buffer.length; + remaining -= buffer.length; + continue; + } + + int available = buffer.length - bufferPos; + int toCopy = Math.min(remaining, available); + System.arraycopy(b, offset, buffer, bufferPos, toCopy); + bufferPos += toCopy; + offset += toCopy; + remaining -= toCopy; + + if (bufferPos == buffer.length) { + flushChunk(); + } + } + } + + @Override + public void flush() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + + // Flush any buffered data as a chunk + if (bufferPos > 0) { + flushChunk(); + } + + // Flush underlying stream + delegate.flush(); + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + + closed = true; + + // Flush any remaining buffered data + if (bufferPos > 0) { + flushChunk(); + } + + // Write final 0-sized chunk + writeFinalChunk(); + // Flush underlying stream; connection lifecycle is handled by the exchange/pool. + delegate.flush(); + } + + /** + * Flush the current buffer as a chunk. + */ + private void flushChunk() throws IOException { + if (bufferPos == 0) { + return; + } + + writeChunk(buffer, 0, bufferPos); + bufferPos = 0; + } + + /** + * Write a chunk with the given data. + * + *

Format: {size-in-hex}\r\n{data}\r\n + */ + private void writeChunk(byte[] data, int off, int len) throws IOException { + delegate.writeAscii(Integer.toHexString(len)); + delegate.writeAscii("\r\n"); + delegate.write(data, off, len); + delegate.writeAscii("\r\n"); + } + + /** + * Write the final 0-sized chunk with optional trailers. + * + *

Format: 0\r\n[trailer-name: trailer-value\r\n]*\r\n + */ + private void writeFinalChunk() throws IOException { + delegate.writeAscii("0\r\n"); + + if (trailers != null) { + trailers.forEachEntry(delegate, (d, name, value) -> { + try { + d.writeAscii(name); + d.writeAscii(": "); + d.writeAscii(value); + d.writeAscii("\r\n"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + + delegate.writeAscii("\r\n"); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/CloseReleasingResponseInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/CloseReleasingResponseInputStream.java new file mode 100644 index 0000000000..1c24dd1917 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/CloseReleasingResponseInputStream.java @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +final class CloseReleasingResponseInputStream extends InputStream { + private final H1Exchange exchange; + private final InputStream delegate; + private boolean closed; + + CloseReleasingResponseInputStream(H1Exchange exchange, InputStream delegate) { + this.exchange = exchange; + this.delegate = delegate; + } + + @Override + public int read() throws IOException { + if (closed) { + return -1; + } + int result = delegate.read(); + if (result == -1) { + close(); + } + return result; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (closed) { + return -1; + } + int result = delegate.read(b, off, len); + if (result == -1) { + close(); + } + return result; + } + + @Override + public long skip(long n) throws IOException { + if (closed) { + return 0; + } + return delegate.skip(n); + } + + @Override + public int available() throws IOException { + return closed ? 0 : delegate.available(); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + if (closed) { + return 0; + } + try { + return delegate.transferTo(out); + } finally { + close(); + } + } + + @Override + public void close() throws IOException { + if (!closed) { + closed = true; + exchange.responseBodyClosed(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FailingOutputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FailingOutputStream.java new file mode 100644 index 0000000000..7c2f3020d3 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FailingOutputStream.java @@ -0,0 +1,39 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * OutputStream that immediately throws a pre-existing exception on any write operation. + * Used when Expect: 100-continue fails before body transmission. + * + *

Close is a no-op since there's nothing to clean up. The exception is thrown when the caller attempts to write, + * not when they clean up. + */ +final class FailingOutputStream extends OutputStream { + private final IOException exception; + + FailingOutputStream(IOException exception) { + this.exception = exception; + } + + @Override + public void write(int b) throws IOException { + throw exception; + } + + @Override + public void flush() throws IOException { + throw exception; + } + + @Override + public void close() { + // No-op: nothing to close + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseChannel.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseChannel.java new file mode 100644 index 0000000000..7c5bafd356 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseChannel.java @@ -0,0 +1,118 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ReadableByteChannel; + +final class FixedLengthResponseChannel implements ReadableByteChannel { + private final H1Exchange h1Exchange; + private final UnsyncBufferedInputStream buffered; + private final ReadableByteChannel channel; + private long remaining; + private boolean open = true; + private boolean completed; + + FixedLengthResponseChannel( + H1Exchange h1Exchange, + UnsyncBufferedInputStream buffered, + ReadableByteChannel channel, + long remaining + ) { + this.h1Exchange = h1Exchange; + this.buffered = buffered; + this.channel = channel; + this.remaining = remaining; + } + + @Override + public int read(ByteBuffer dst) throws IOException { + if (completed) { + return -1; + } + if (!open) { + throw new ClosedChannelException(); + } + if (!dst.hasRemaining()) { + return 0; + } + if (remaining == 0) { + finish(); + return -1; + } + + int originalLimit = dst.limit(); + if (remaining < dst.remaining()) { + dst.limit(dst.position() + (int) remaining); + } + try { + int total = drainBuffered(dst); + if (dst.hasRemaining() && remaining > 0) { + int n = channel.read(dst); + if (n < 0) { + if (total != 0) { + return total; + } + throw prematureEof(); + } + total += n; + remaining -= n; + } + if (remaining == 0) { + finish(); + } + return total; + } finally { + dst.limit(originalLimit); + } + } + + private int drainBuffered(ByteBuffer dst) { + int bufferedBytes = Math.min(buffered.buffered(), dst.remaining()); + if (bufferedBytes == 0) { + return 0; + } + dst.put(buffered.buffer(), buffered.position(), bufferedBytes); + buffered.consume(bufferedBytes); + remaining -= bufferedBytes; + return bufferedBytes; + } + + @Override + public boolean isOpen() { + return open && !completed; + } + + @Override + public void close() throws IOException { + if (open) { + open = false; + try { + if (remaining > 0) { + buffered.discard(remaining); + remaining = 0; + } + } finally { + finish(); + } + } + } + + private void finish() throws IOException { + if (!completed) { + completed = true; + open = false; + h1Exchange.close(); + } + } + + private IOException prematureEof() { + return new IOException("Premature EOF: expected " + remaining + + " more bytes based on Content-Length"); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseInputStream.java new file mode 100644 index 0000000000..63e1e58abd --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/FixedLengthResponseInputStream.java @@ -0,0 +1,157 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +final class FixedLengthResponseInputStream extends InputStream { + private final H1Exchange exchange; + private final UnsyncBufferedInputStream delegate; + private long remaining; + private boolean closed; + + FixedLengthResponseInputStream(H1Exchange exchange, UnsyncBufferedInputStream delegate, long length) { + this.exchange = exchange; + this.delegate = delegate; + this.remaining = length; + } + + @Override + public int read() throws IOException { + if (closed) { + return -1; + } + if (remaining == 0) { + complete(); + return -1; + } + + int b = delegate.read(); + if (b == -1) { + throw prematureEof(); + } + + remaining--; + if (remaining == 0) { + complete(); + } + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + if (closed) { + return -1; + } + if (len == 0) { + return 0; + } + if (remaining == 0) { + complete(); + return -1; + } + + int n = delegate.read(b, off, (int) Math.min(len, remaining)); + if (n == -1) { + throw prematureEof(); + } + + remaining -= n; + if (remaining == 0) { + complete(); + } + return n; + } + + @Override + public long skip(long n) throws IOException { + if (closed || remaining == 0 || n <= 0) { + return 0; + } + + long skipped = delegate.skip(Math.min(n, remaining)); + remaining -= skipped; + if (remaining == 0) { + complete(); + } + return skipped; + } + + @Override + public int available() throws IOException { + if (closed || remaining == 0) { + return 0; + } + return (int) Math.min(delegate.available(), remaining); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + if (closed || remaining == 0) { + return 0; + } + + long transferred = 0; + while (remaining > 0) { + int buffered = delegate.buffered(); + if (buffered > 0) { + int n = (int) Math.min(buffered, remaining); + out.write(delegate.buffer(), delegate.position(), n); + delegate.consume(n); + remaining -= n; + transferred += n; + if (remaining == 0) { + complete(); + } + continue; + } + + int n = delegate.readDirect(delegate.buffer(), 0, (int) Math.min(delegate.buffer().length, remaining)); + if (n == -1) { + throw prematureEof(); + } + out.write(delegate.buffer(), 0, n); + remaining -= n; + transferred += n; + if (remaining == 0) { + complete(); + } + } + return transferred; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + try { + if (remaining > 0) { + delegate.discard(remaining); + remaining = 0; + } + } finally { + complete(); + } + } + + private void complete() throws IOException { + if (!closed) { + closed = true; + exchange.responseBodyClosed(); + } + } + + private IOException prematureEof() { + return new IOException("Premature EOF: expected " + remaining + + " more bytes based on Content-Length"); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Connection.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Connection.java new file mode 100644 index 0000000000..14d8411af4 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Connection.java @@ -0,0 +1,194 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.net.ssl.SSLSession; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.connection.ConnectionTransport; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * HTTP/1.1 connection implementation. + * + *

Manages a single TCP connection for HTTP/1.1 communication. HTTP/1.1 allows only one request/response exchange + * at a time (no multiplexing like HTTP/2). + * + *

Connection Reuse

+ *

Supports persistent connections. After each exchange, the connection can be returned to the pool for reuse if: + *

    + *
  • The response version and connection headers permit persistent reuse
  • + *
  • The response body was fully read
  • + *
  • No errors occurred during the exchange
  • + *
+ * + *

Thread Safety

+ *

This class is thread-safe for {@link #newExchange} - only one exchange can be active at a time. + * Concurrent calls to {@code newExchange()} will fail with an exception if another exchange is already active. + */ +public final class H1Connection implements HttpConnection { + /** + * Buffer used for parsing the HTTP/1.x status line and each header line. + * This bounds any single response line to 8KB (status line or header line). + */ + static final int RESPONSE_LINE_BUFFER_SIZE = 8192; + private static final int INPUT_BUFFER_SIZE = 64 * 1024; + private static final int OUTPUT_BUFFER_SIZE = 8 * 1024; + + private static final InternalLogger LOGGER = InternalLogger.getLogger(H1Connection.class); + + private final ConnectionTransport transport; + private final UnsyncBufferedInputStream socketIn; + private final UnsyncBufferedOutputStream socketOut; + private final Route route; + private final H1Exchange exchange; + + // HTTP/1.1: only one exchange at a time + private final AtomicBoolean inUse = new AtomicBoolean(false); + private volatile boolean keepAlive = true; + private volatile boolean active = true; + + /** + * Create an HTTP/1.1 connection from a transport. + * + * @param transport the connected transport (TLS handshake must be complete if secure) + * @param route Connection route + * @param readTimeout timeout for read operations + * @throws IOException if streams cannot be obtained + */ + public H1Connection(ConnectionTransport transport, Route route, Duration readTimeout) throws IOException { + this.transport = transport; + this.socketIn = new UnsyncBufferedInputStream(transport.inputStream(), INPUT_BUFFER_SIZE); + this.socketOut = new UnsyncBufferedOutputStream(transport.outputStream(), OUTPUT_BUFFER_SIZE); + this.route = route; + this.exchange = new H1Exchange(this, route); + + if (readTimeout != null && !readTimeout.isZero()) { + transport.setReadTimeout((int) readTimeout.toMillis()); + } + } + + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + if (!active) { + throw new IOException("Connection is closed"); + } else if (!inUse.compareAndSet(false, true)) { + throw new IOException("Connection already in use (concurrent exchange attempted)"); + } + + try { + return exchange.init(options.applyExpectContinue(request)); + } catch (IOException e) { + releaseExchange(); + throw e; + } + } + + @Override + public HttpVersion httpVersion() { + return HttpVersion.HTTP_1_1; + } + + @Override + public boolean isActive() { + return active && keepAlive; + } + + @Override + public boolean validateForReuse() { + if (!active || !keepAlive) { + return false; + } + + if (!transport.isOpen()) { + LOGGER.debug("Connection to {} is closed", route); + markInactive(); + return false; + } + + try { + if (socketIn.available() > 0) { + LOGGER.debug("Unexpected data available on idle connection to {}", route); + markInactive(); + return false; + } + } catch (IOException e) { + LOGGER.debug("IOException checking connection state for {}: {}", route, e.getMessage()); + markInactive(); + return false; + } + + return true; + } + + @Override + public Route route() { + return route; + } + + @Override + public SSLSession sslSession() { + return transport.sslSession(); + } + + @Override + public String negotiatedProtocol() { + return transport.negotiatedProtocol(); + } + + @Override + public void close() throws IOException { + active = false; + transport.close(); + } + + void releaseExchange() { + inUse.set(false); + } + + void setSocketTimeout(int timeoutMs) throws IOException { + transport.setReadTimeout(timeoutMs); + } + + int getSocketTimeout() throws IOException { + return transport.getReadTimeout(); + } + + void setKeepAlive(boolean keepAlive) { + this.keepAlive = keepAlive; + } + + boolean isKeepAlive() { + return keepAlive; + } + + UnsyncBufferedInputStream getInputStream() { + return socketIn; + } + + UnsyncBufferedOutputStream getOutputStream() { + return socketOut; + } + + ReadableByteChannel getReadableChannel() throws IOException { + return transport.readableChannel(); + } + + void markInactive() { + if (active) { + LOGGER.debug("Marking connection inactive to {}", route); + this.active = false; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Exchange.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Exchange.java new file mode 100644 index 0000000000..8c453c3efd --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Exchange.java @@ -0,0 +1,836 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.SocketTimeoutException; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.StandardCharsets; +import software.amazon.smithy.java.http.api.HeaderName; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.api.ModifiableHttpHeaders; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * HTTP/1.1 exchange implementation, handling a single request/response over a connection. + * + *

Request/Response Flow

+ *

HTTP/1.1 allows one active exchange per connection. This class enforces the client-side ordering: + *

    + *
  1. Request line and headers are written when the exchange is initialized
  2. + *
  3. Request body is written via {@link #writeRequestBody(DataStream)}, unless a final Expect response skips it
  4. + *
  5. Final response is read via {@link #responseStatusCode()}, {@link #responseHeaders()}, {@link #responseBody()}
  6. + *
+ * + *

Expect: 100-continue

+ *

When the request includes {@code Expect: 100-continue}, the client: + *

    + *
  1. Sends headers and waits for 100 Continue response
  2. + *
  3. If server sends 100, proceeds to send body
  4. + *
  5. If server sends 4xx/5xx, skips body transmission
  6. + *
  7. If server doesn't respond within timeout, proceeds anyway
  8. + *
+ * + *

Proxy Support

+ *

When used through a non-tunneled HTTP proxy, requests are formatted with absolute URIs instead of relative paths: + *

    + *
  • Direct/tunneled: {@code GET /users HTTP/1.1}
  • + *
  • HTTP proxy: {@code GET http://api.example.com/users HTTP/1.1}
  • + *
+ * + *

Transfer Encoding

+ *

Supports both chunked transfer encoding and fixed Content-Length for request and response bodies. + */ +final class H1Exchange implements HttpExchange { + + private static final int MAX_RESPONSE_HEADER_COUNT = 512; + private static final long DEFAULT_CONTINUE_TIMEOUT_MS = 1000; // 1 second + + // Pre-allocated byte arrays for constant HTTP strings + private static final byte[] HTTP_1_1_CRLF = " HTTP/1.1\r\n".getBytes(StandardCharsets.US_ASCII); + private static final byte[] CRLF = "\r\n".getBytes(StandardCharsets.US_ASCII); + private static final byte[] COLON_SPACE = ": ".getBytes(StandardCharsets.US_ASCII); + private static final byte[] HOST_HEADER = "Host: ".getBytes(StandardCharsets.US_ASCII); + + private final H1Connection connection; + private final Route route; + private final byte[] responseLineBuffer = new byte[H1Connection.RESPONSE_LINE_BUFFER_SIZE]; + + private HttpRequest request; + private OutputStream requestOut; + private InputStream responseIn; + private ChunkedInputStream chunkedResponseIn; // Reference for trailer access + private HttpHeaders responseHeaders; + private HttpVersion responseVersion; + private long responseContentLength = -1; + private boolean responseChunked; + // Keep-alive override from the response Connection header: null = not specified (use protocol + // default), TRUE = keep-alive, FALSE = close. Set by captureControlHeader alongside the other + // response header fields. + private Boolean responseKeepAlive; + private int statusCode = -1; + private boolean requestWritten = false; + private boolean expectContinueHandled = false; + private boolean closed; + private byte[] chunkedRequestBuffer; + + /** + * Create a reusable HTTP/1.1 exchange. + * + * @param connection the HTTP/1.1 connection to use + * @param route the route this connection is for (needed for proxy formatting) + */ + H1Exchange(H1Connection connection, Route route) { + this.connection = connection; + this.route = route; + } + + /** + * Initializes this exchange for the next request on the connection. + * + *

Immediately writes request line and headers to the connection. + * + * @param request the HTTP request to send + * @return this reusable exchange + * @throws IOException if writing request line or headers fails + */ + H1Exchange init(HttpRequest request) throws IOException { + this.request = request; + this.requestOut = null; + this.responseIn = null; + this.chunkedResponseIn = null; + this.responseHeaders = null; + this.responseVersion = null; + this.responseContentLength = -1; + this.responseChunked = false; + this.responseKeepAlive = null; + this.statusCode = -1; + this.requestWritten = false; + this.expectContinueHandled = false; + this.closed = false; + + // Write request line and headers directly to output buffer + UnsyncBufferedOutputStream out = connection.getOutputStream(); + writeRequestLine(out); + writeHeaders(out, request.headers()); + + // Only flush if no body - otherwise body write will flush + if (request.body() == null || request.body().contentLength() == 0) { + out.flush(); + requestWritten = true; + } + + return this; + } + + @Override + public HttpRequest request() { + return request; + } + + OutputStream requestBody() { + if (requestOut == null) { + UnsyncBufferedOutputStream socketOut = connection.getOutputStream(); + var headers = request.headers(); + + // Handle Expect: 100-continue before creating output stream + String expectHeader = headers.firstValue(HeaderName.EXPECT); + if (expectHeader != null && expectHeader.equalsIgnoreCase("100-continue")) { + try { + handleExpectContinue(); + } catch (IOException e) { + // Wrap exception for later throwing when writing + requestOut = new FailingOutputStream(e); + return requestOut; + } + if (requestWritten) { + requestOut = OutputStream.nullOutputStream(); + return requestOut; + } + } + + String transferEncoding = headers.firstValue(HeaderName.TRANSFER_ENCODING); + if ("chunked".equalsIgnoreCase(transferEncoding)) { + // RFC 9110 Section 6.3: Content-Length MUST NOT be sent with Transfer-Encoding + if (headers.firstValue(HeaderName.CONTENT_LENGTH) != null) { + throw new IllegalArgumentException( + "Request cannot have both Content-Length and Transfer-Encoding headers"); + } + requestOut = new ChunkedOutputStream(socketOut, chunkedRequestBuffer()); + } else { + requestOut = new NonClosingOutputStream(socketOut); + } + } + return requestOut; + } + + @Override + public void writeRequestBody(DataStream body) throws IOException { + try (OutputStream out = requestBody()) { + if (body != null) { + // Use writeTo, not asInputStream().transferTo: a body can flush per message via writeTo, + // which for a chunked request sends each message as its own chunk. transferTo would + // coalesce them, deadlocking a send-then-await-reply event protocol. + body.writeTo(out); + } + } + } + + @Override + public InputStream responseBody() throws IOException { + if (responseIn == null) { + ensureRequestComplete(); + if (statusCode == -1) { + parseStatusLineAndHeaders(); + } + responseIn = createResponseStream(); + } + return responseIn; + } + + @Override + public ReadableByteChannel responseBodyChannel() throws IOException { + if (responseIn != null) { + return Channels.newChannel(responseIn); + } + + ensureRequestComplete(); + if (statusCode == -1) { + parseStatusLineAndHeaders(); + } + + if (responseChunked || responseContentLength < 0) { + return Channels.newChannel(responseBody()); + } + + if (noBodyResponseStatus(statusCode) || "HEAD".equalsIgnoreCase(request.method())) { + return new FixedLengthResponseChannel(this, + connection.getInputStream(), + connection.getReadableChannel(), + 0); + } + + return new FixedLengthResponseChannel(this, + connection.getInputStream(), + connection.getReadableChannel(), + responseContentLength); + } + + @Override + public void discardResponseBody() throws IOException { + if (responseIn != null) { + try { + responseIn.transferTo(OutputStream.nullOutputStream()); + } finally { + responseIn.close(); + } + return; + } + + ensureRequestComplete(); + if (statusCode == -1) { + parseStatusLineAndHeaders(); + } + + if (noBodyResponseStatus(statusCode) || "HEAD".equalsIgnoreCase(request.method())) { + close(); + } else if (responseChunked) { + discardChunkedResponseBody(connection.getInputStream()); + close(); + } else if (responseContentLength >= 0) { + connection.getInputStream().discard(responseContentLength); + close(); + } else { + responseIn = createResponseStream(); + try { + responseIn.transferTo(OutputStream.nullOutputStream()); + } finally { + responseIn.close(); + } + } + } + + @Override + public void setRequestTrailers(HttpHeaders trailers) { + if (!(requestOut instanceof ChunkedOutputStream cos)) { + throw new IllegalStateException("Request trailers require chunked transfer encoding"); + } + cos.setTrailers(trailers); + } + + @Override + public HttpHeaders responseHeaders() throws IOException { + if (responseHeaders == null) { + ensureRequestComplete(); + parseStatusLineAndHeaders(); + } + return responseHeaders; + } + + @Override + public int responseStatusCode() throws IOException { + if (statusCode == -1) { + ensureRequestComplete(); + parseStatusLineAndHeaders(); + } + return statusCode; + } + + @Override + public HttpVersion responseVersion() throws IOException { + if (responseVersion == null) { + ensureRequestComplete(); + parseStatusLineAndHeaders(); + } + return responseVersion; + } + + @Override + public void close() throws IOException { + if (!closed) { + closed = true; + try { + if (responseIn != null) { + responseIn.close(); + } + if (requestOut != null) { + requestOut.close(); + } + } finally { + connection.releaseExchange(); + } + } + } + + void responseBodyClosed() throws IOException { + if (!closed) { + closed = true; + try { + if (requestOut != null) { + requestOut.close(); + } + } finally { + connection.releaseExchange(); + } + } + } + + /** + * Get trailer headers from chunked transfer encoding response. + * + *

Trailers are only available for chunked responses after the entire + * response body has been read. For non-chunked responses, this returns null. + * + * @return trailer headers, or null if no trailers were received + */ + @Override + public HttpHeaders responseTrailerHeaders() { + // Trailers are only available from chunked responses + if (chunkedResponseIn != null) { + return chunkedResponseIn.getTrailers(); + } + return null; + } + + /** + * Handle Expect: 100-continue negotiation. + * + *

Waits up to N seconds for 100 Continue response: + *

    + *
  • 100 Continue → proceed with body
  • + *
  • 417 Expectation Failed → throw exception
  • + *
  • Other response → parse as final response, skip body
  • + *
  • Timeout → proceed with body anyway
  • + *
+ * + * @throws IOException if error response received or I/O fails + */ + private void handleExpectContinue() throws IOException { + if (expectContinueHandled) { + return; + } + expectContinueHandled = true; + + // The request line and headers were buffered in init() but not flushed (a body is present, and + // the body write normally flushes). For Expect: 100-continue we must put the headers on the wire + // now -- otherwise the server never sees the request, never sends the interim 100, and we block + // until the read times out (which, on the epoll transport, closes the connection). + connection.getOutputStream().flush(); + + UnsyncBufferedInputStream in = connection.getInputStream(); + + // Set socket timeout for 100-continue response + int originalTimeout; + try { + originalTimeout = connection.getSocketTimeout(); + connection.setSocketTimeout((int) DEFAULT_CONTINUE_TIMEOUT_MS); + } catch (IOException e) { + // Can't set timeout - proceed without waiting + return; + } + + try { + // Try to read 100 Continue response + int lineLen = readLine(in); + + if (lineLen <= 0) { + // Timeout waiting for response - proceed with body + return; + } + + int code = parseStatusLine(responseLineBuffer, lineLen); + + if (code == 100) { + // 100 Continue received - read and discard headers, proceed with body + while (readLine(in) > 0) { + // Skip header lines until empty line + } + } else { + // Server sent final response without 100 Continue + // Parse as final response, must not send body + parseStatusAndHeaders(code, in); + requestWritten = true; // Skip body transmission + } + } catch (SocketTimeoutException e) { + // Timeout waiting for 100 Continue - proceed with body anyway + // Some servers don't support 100-continue and just ignore it + } finally { + // Restore original timeout + try { + connection.setSocketTimeout(originalTimeout); + } catch (IOException ignored) {} + } + } + + private int readLine(UnsyncBufferedInputStream in) throws IOException { + return in.readLine(responseLineBuffer, H1Connection.RESPONSE_LINE_BUFFER_SIZE); + } + + private void writeRequestLine(UnsyncBufferedOutputStream out) throws IOException { + out.writeAscii(request.method()); + out.write(' '); + + var uri = request.uri(); + if ("CONNECT".equals(request.method())) { + // CONNECT uses authority-form: host:port + out.writeAscii(uri.getHost()); + int port = uri.getPort(); + if (port != -1) { + out.write(':'); + out.writeAscii(Integer.toString(port)); + } + } else if (isHttpProxyWithoutTunnel()) { + out.writeAscii(uri.toString()); + } else { + String path = uri.getPath(); + if (path.isEmpty()) { + out.write('/'); + } else { + out.writeAscii(path); + } + + String query = uri.getQuery(); + if (query != null && !query.isEmpty()) { + out.write('?'); + out.writeAscii(query); + } + } + + out.write(HTTP_1_1_CRLF); + } + + /** + * Check if this request is going through an HTTP proxy without a tunnel. + * + * @return true if absolute URI format is needed + */ + private boolean isHttpProxyWithoutTunnel() { + return route != null && (route.usesProxy() && !route.isSecure()); + } + + private void writeHeaders(UnsyncBufferedOutputStream out, HttpHeaders headers) throws IOException { + // Ensure Host header is present + if (headers.firstValue(HeaderName.HOST) == null) { + var uri = request.uri(); + out.write(HOST_HEADER); + out.writeAscii(uri.getHost()); + int port = uri.getPort(); + // Include port only if non-default for the scheme + if (port != -1 && port != defaultPort(uri.getScheme())) { + out.write(':'); + out.writeAscii(Integer.toString(port)); + } + out.write(CRLF); + } + + try { + // Write all headers + headers.forEachEntry(out, (o, name, value) -> { + try { + o.writeAscii(name); + o.write(COLON_SPACE); + o.writeAscii(value); + o.write(CRLF); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + + // Blank line to end headers + out.write(CRLF); + } + + private void ensureRequestComplete() throws IOException { + if (!requestWritten) { + if (requestOut != null) { + requestOut.close(); + } + connection.getOutputStream().flush(); + requestWritten = true; + } + } + + private byte[] chunkedRequestBuffer() { + if (chunkedRequestBuffer == null) { + chunkedRequestBuffer = new byte[ChunkedOutputStream.DEFAULT_CHUNK_SIZE]; + } + return chunkedRequestBuffer; + } + + private void parseStatusLineAndHeaders() throws IOException { + // If we already parsed during Expect: 100-continue, return + if (statusCode != -1) { + return; + } + + UnsyncBufferedInputStream in = connection.getInputStream(); + + try { + // Loop to skip 1xx interim responses (RFC 9110 Section 15.2) + // Examples: 100 Continue, 103 Early Hints + int code; + do { + int lineLen = readLine(in); + if (lineLen <= 0) { + throw new IOException("Empty HTTP response from " + request.uri()); + } + code = parseStatusLine(responseLineBuffer, lineLen); + + if (code >= 100 && code < 200) { + // Skip 1xx interim response headers + while (readLine(in) > 0) { + // Discard header lines until empty line + } + } + } while (code >= 100 && code < 200); + + parseStatusAndHeaders(code, in); + } catch (SocketTimeoutException e) { + connection.markInactive(); + throw new SocketTimeoutException("Read timeout while waiting for HTTP response headers from " + + request.uri() + " (check read timeout configuration)"); + } + } + + /** + * Parse status line. Expects "HTTP/1.x NNN ...". + * Sets responseVersion and returns status code. + * Also detects HTTP/1.0 and disables keep-alive (HTTP/1.0 defaults to close). + */ + private int parseStatusLine(byte[] buf, int len) throws IOException { + // Validate HTTP version - must be "HTTP/1.0" or "HTTP/1.1". + // Minimum valid status line: "HTTP/1.x NNN" = 12 bytes + if (len < 12 + || buf[0] != 'H' + || buf[1] != 'T' + || buf[2] != 'T' + || buf[3] != 'P' + || buf[4] != '/' + || buf[5] != '1' + || buf[6] != '.' + || buf[8] != ' ') { + throw new IOException("Malformed HTTP response status line: " + + new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + byte minor = buf[7]; + if (minor == '1') { + responseVersion = HttpVersion.HTTP_1_1; + } else if (minor == '0') { + responseVersion = HttpVersion.HTTP_1_0; + connection.setKeepAlive(false); // HTTP/1.0 defaults to Connection: close + } else { + throw new IOException("Unsupported HTTP version: HTTP/1." + (char) minor); + } + + // Parse 3-digit status code directly from bytes (positions 9, 10, 11) + byte c1 = buf[9]; + byte c2 = buf[10]; + byte c3 = buf[11]; + + if (c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' || c3 < '0' || c3 > '9') { + throw new IOException("Invalid status code in HTTP response: " + + new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + return ((c1 - '0') * 100) + ((c2 - '0') * 10) + (c3 - '0'); + } + + private void parseStatusAndHeaders(int code, UnsyncBufferedInputStream in) throws IOException { + this.statusCode = code; + if (statusCode < 100 || statusCode > 599) { + throw new IOException("Invalid HTTP status code: " + statusCode); + } + + ModifiableHttpHeaders headers = HttpHeaders.ofModifiable(); + int headerCount = 0; + + int lineLen; + while ((lineLen = readLine(in)) > 0) { + headerCount++; + if (headerCount > MAX_RESPONSE_HEADER_COUNT) { + throw new IOException("Too many HTTP headers: " + headerCount + + " exceeds maximum of " + MAX_RESPONSE_HEADER_COUNT); + } + + int colon = H1Utils.findHeaderColon(responseLineBuffer, lineLen); + if (colon <= 0) { + throw new IOException("Invalid header line: " + + new String(responseLineBuffer, 0, lineLen, StandardCharsets.US_ASCII)); + } + int valueStart = H1Utils.headerValueStart(responseLineBuffer, colon, lineLen); + int valueEnd = H1Utils.headerValueEnd(responseLineBuffer, valueStart, lineLen); + String name = H1Utils.parseHeaderLine(responseLineBuffer, colon, valueStart, valueEnd, headers); + captureControlHeader(responseLineBuffer, valueStart, valueEnd, name); + } + + this.responseHeaders = headers; + + if (responseKeepAlive != null) { + connection.setKeepAlive(responseKeepAlive); + } + } + + // Records the content-length, transfer-encoding, and connection (keep-alive) response headers into + // the corresponding instance fields. Other headers (including content-type) are still parsed into + // responseHeaders by the caller; they just don't drive transport behavior, so they are ignored here. + private void captureControlHeader(byte[] line, int valueStart, int valueEnd, String name) throws IOException { + switch (name) { + case "content-length" -> { + long length = parseContentLength(line, valueStart, valueEnd); + if (responseContentLength >= 0 && responseContentLength != length) { + throw new IOException("Conflicting Content-Length headers: " + + responseContentLength + " and " + length); + } + responseContentLength = length; + } + case "transfer-encoding" -> responseChunked = containsChunked(line, valueStart, valueEnd); + case "connection" -> { + if (equalsIgnoreCase(line, valueStart, valueEnd, "close")) { + responseKeepAlive = Boolean.FALSE; + } else if (equalsIgnoreCase(line, valueStart, valueEnd, "keep-alive")) { + responseKeepAlive = Boolean.TRUE; + } + } + default -> { + } + } + } + + private static boolean isOWS(byte b) { + return b == ' ' || b == '\t'; + } + + private static long parseContentLength(byte[] line, int start, int end) throws IOException { + if (start == end) { + throw new IOException("Invalid empty Content-Length header"); + } + long result = 0; + for (int i = start; i < end; i++) { + byte b = line[i]; + if (b < '0' || b > '9') { + throw new IOException("Invalid Content-Length header: " + + new String(line, start, end - start, StandardCharsets.US_ASCII)); + } + result = result * 10 + (b - '0'); + if (result < 0) { + throw new IOException("Invalid Content-Length header: value overflow"); + } + } + return result; + } + + private InputStream createResponseStream() throws IOException { + UnsyncBufferedInputStream socketIn = connection.getInputStream(); + + // No body for certain status codes or HEAD response, regardless of Content-Length. + if (noBodyResponseStatus(statusCode) || "HEAD".equalsIgnoreCase(request.method())) { + return new FixedLengthResponseInputStream(this, socketIn, 0); + } + + if (responseChunked) { + chunkedResponseIn = new ChunkedInputStream(socketIn, this, responseLineBuffer); + return chunkedResponseIn; + } + + if (responseContentLength >= 0) { + return new FixedLengthResponseInputStream(this, socketIn, responseContentLength); + } + + // Read until close for close-delimited responses. + connection.setKeepAlive(false); + return new CloseReleasingResponseInputStream(this, socketIn); + } + + /** + * Fast check for "chunked" token in transfer-encoding value. + */ + private static boolean containsChunked(byte[] value, int start, int end) { + int len = end - start; + if (len < 7) { + return false; + } + + // Fast path: exact match + if (len == 7 && equalsIgnoreCase(value, start, end, "chunked")) { + return true; + } + + int tokenStart = start; + for (int i = start; i <= end; i++) { + if (i == end || value[i] == ',') { + int tokenEnd = i; + while (tokenStart < tokenEnd && isOWS(value[tokenStart])) { + tokenStart++; + } + while (tokenEnd > tokenStart && isOWS(value[tokenEnd - 1])) { + tokenEnd--; + } + if (tokenEnd - tokenStart == 7 && equalsIgnoreCase(value, tokenStart, tokenEnd, "chunked")) { + return true; + } + tokenStart = i + 1; + } + } + + return false; + } + + private static boolean equalsIgnoreCase(byte[] bytes, int start, int end, String expected) { + if (end - start != expected.length()) { + return false; + } + for (int i = 0; i < expected.length(); i++) { + byte b = bytes[start + i]; + char c = expected.charAt(i); + if ((b | 0x20) != c) { + return false; + } + } + return true; + } + + private void discardChunkedResponseBody(UnsyncBufferedInputStream in) throws IOException { + for (;;) { + int lineLen = readLine(in); + long chunkSize = parseChunkSize(responseLineBuffer, lineLen); + + if (chunkSize == 0) { + discardTrailers(in); + return; + } + + in.discard(chunkSize); + readChunkCrlf(in); + } + } + + private void discardTrailers(UnsyncBufferedInputStream in) throws IOException { + int trailerCount = 0; + while (readLine(in) > 0) { + trailerCount++; + if (trailerCount > MAX_RESPONSE_HEADER_COUNT) { + throw new IOException("Too many HTTP trailers: " + trailerCount + + " exceeds maximum of " + MAX_RESPONSE_HEADER_COUNT); + } + } + } + + private static long parseChunkSize(byte[] line, int lineLen) throws IOException { + if (lineLen <= 0) { + throw new IOException("Empty chunk size line"); + } + + int sizeEnd = lineLen; + for (int i = 0; i < lineLen; i++) { + byte b = line[i]; + if (b == ';' || isOWS(b)) { + sizeEnd = i; + break; + } + } + + if (sizeEnd == 0) { + throw new IOException("Missing chunk size"); + } + + long value = 0; + for (int i = 0; i < sizeEnd; i++) { + byte b = line[i]; + int digit; + if (b >= '0' && b <= '9') { + digit = b - '0'; + } else if (b >= 'a' && b <= 'f') { + digit = 10 + (b - 'a'); + } else if (b >= 'A' && b <= 'F') { + digit = 10 + (b - 'A'); + } else { + throw new IOException("Invalid hex character in chunk size: " + (char) b); + } + if ((value & 0xF000_0000_0000_0000L) != 0) { + throw new IOException("HTTP/1.1 chunk size overflow"); + } + value = (value << 4) | digit; + } + return value; + } + + private static void readChunkCrlf(UnsyncBufferedInputStream in) throws IOException { + int cr = in.read(); + int lf = in.read(); + if (cr == -1 || lf == -1) { + throw new IOException("Unexpected end of stream: expected CRLF after chunk data"); + } + if (cr != '\r' || lf != '\n') { + throw new IOException(String.format("Expected CRLF after chunk data, got 0x%02X 0x%02X", cr, lf)); + } + } + + /** + * Check if status code indicates no response body per RFC 9110 Section 6.4.1. + */ + private static boolean noBodyResponseStatus(int statusCode) { + return statusCode == 204 || statusCode == 304 || (statusCode >= 100 && statusCode < 200); + } + + /** + * Get default port for scheme (80 for http or unknown, 443 for https). + */ + private static int defaultPort(String scheme) { + return "https".equalsIgnoreCase(scheme) ? 443 : 80; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Utils.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Utils.java new file mode 100644 index 0000000000..a48bf3187f --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/H1Utils.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.nio.charset.StandardCharsets; +import software.amazon.smithy.java.http.api.HeaderName; +import software.amazon.smithy.java.http.api.ModifiableHttpHeaders; + +/** + * HTTP/1.1 parsing utilities. + * + *

Uses {@link HeaderName} for header name normalization. + */ +final class H1Utils { + + private H1Utils() {} + + /** + * Parse a header line and add it to the headers collection. + * + * @param buf byte buffer containing header line + * @param len length of header line (excluding CRLF) + * @param headers collection to add the parsed header to + * @return the canonical header name, or null if line is malformed (no colon) + */ + static String parseHeaderLine(byte[] buf, int len, ModifiableHttpHeaders headers) { + int colon = findHeaderColon(buf, len); + if (colon <= 0) { + return null; + } + + int valueStart = headerValueStart(buf, colon, len); + int valueEnd = headerValueEnd(buf, valueStart, len); + return parseHeaderLine(buf, colon, valueStart, valueEnd, headers); + } + + static String parseHeaderLine( + byte[] buf, + int colon, + int valueStart, + int valueEnd, + ModifiableHttpHeaders headers + ) { + // Normalize header name using centralized registry + String name = HeaderName.canonicalize(buf, 0, colon); + + String value = new String(buf, valueStart, valueEnd - valueStart, StandardCharsets.US_ASCII); + headers.addHeaderCanonical(name, value); + return name; + } + + static int findHeaderColon(byte[] buf, int len) { + for (int i = 0; i < len; i++) { + if (buf[i] == ':') { + return i; + } + } + return -1; + } + + static int headerValueStart(byte[] buf, int colon, int len) { + int valueStart = colon + 1; + while (valueStart < len && isOWS(buf[valueStart])) { + valueStart++; + } + return valueStart; + } + + static int headerValueEnd(byte[] buf, int valueStart, int len) { + int valueEnd = len; + while (valueEnd > valueStart && isOWS(buf[valueEnd - 1])) { + valueEnd--; + } + return valueEnd; + } + + /** + * Check if byte is optional whitespace (OWS) per RFC 9110: SP or HTAB. + */ + private static boolean isOWS(byte b) { + return b == ' ' || b == '\t'; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStream.java new file mode 100644 index 0000000000..e572361bf4 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStream.java @@ -0,0 +1,54 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * OutputStream wrapper that prevents closing the underlying stream. + * + *

Used for HTTP/1.1 request bodies where we don't want to close the socket when the request body is done. + */ +final class NonClosingOutputStream extends OutputStream { + private final OutputStream delegate; + private boolean closed = false; + + public NonClosingOutputStream(OutputStream delegate) { + this.delegate = delegate; + } + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + delegate.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + delegate.write(b, off, len); + } + + @Override + public void flush() throws IOException { + if (!closed) { + delegate.flush(); + } + } + + @Override + public void close() throws IOException { + if (!closed) { + closed = true; + delegate.flush(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStream.java new file mode 100644 index 0000000000..5956edd76a --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStream.java @@ -0,0 +1,422 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * A buffered input stream like {@link java.io.BufferedInputStream}, but without synchronization. + * + *

This class exposes its guts for optimal performance. Be responsible, and note the warnings on each method. + */ +final class UnsyncBufferedInputStream extends InputStream { + private final InputStream in; + private final byte[] buf; + private int pos; + private int limit; + private boolean closed; + + public UnsyncBufferedInputStream(InputStream in, int size) { + if (size <= 0) { + throw new IllegalArgumentException("Buffer size <= 0"); + } + this.in = in; + this.buf = new byte[size]; + } + + /** + * Fills the buffer with data from the underlying stream. + * + * @return the number of bytes read, or -1 if EOF + * @throws IOException if an I/O error occurs + */ + private int fill() throws IOException { + pos = 0; + int n = in.read(buf); + // Keep limit >= 0 so that "pos >= limit" comparisons work correctly after EOF + limit = Math.max(n, 0); + return n; + } + + @Override + public int read() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (pos >= limit && fill() <= 0) { + return -1; + } else { + return buf[pos++] & 0xFF; + } + } + + @Override + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + int n = 0; + + // First, drain the buffer + int avail = limit - pos; + if (avail > 0) { + int toCopy = Math.min(avail, len); + System.arraycopy(buf, pos, b, off, toCopy); + pos += toCopy; + off += toCopy; + len -= toCopy; + n += toCopy; + if (len == 0) { + return n; + } + } + + // If remaining request is large, bypass our buffer to avoid double-copy + if (len >= buf.length) { + int direct = in.read(b, off, len); + if (direct < 0) { + return n == 0 ? -1 : n; + } + return n + direct; + } + + // For smaller remaining requests, refill buffer and copy + if (fill() <= 0) { + return n == 0 ? -1 : n; + } + + int toCopy = Math.min(limit - pos, len); + System.arraycopy(buf, pos, b, off, toCopy); + pos += toCopy; + return n + toCopy; + } + + @Override + public long skip(long n) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (n <= 0) { + return 0; + } + + long remaining = n; + + // First skip what's in the buffer + int avail = limit - pos; + if (avail > 0) { + long skipped = Math.min(avail, remaining); + pos += (int) skipped; + remaining -= skipped; + } + + // Skip in underlying stream only if needed + if (remaining > 0) { + long skippedUnderlying = in.skip(remaining); + if (skippedUnderlying > 0) { + remaining -= skippedUnderlying; + } + } + + return n - remaining; + } + + @Override + public int available() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + int avail = limit - pos; + if (avail < 0) { + avail = 0; + } + return avail + in.available(); + } + + @Override + public void close() throws IOException { + if (!closed) { + closed = true; + in.close(); + } + } + + // Optimized transferTo that doesn't allocate a new buffer. + @Override + public long transferTo(OutputStream out) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + + // First drain what's already buffered + long transferred = 0; + int buffered = limit - pos; + if (buffered > 0) { + out.write(buf, pos, buffered); + pos = limit; + transferred = buffered; + } + + // Then stream the rest using _our_ buffer (super would allocate a buffer) + int n; + while ((n = in.read(buf)) != -1) { + out.write(buf, 0, n); + transferred += n; + } + return transferred; + } + + /** + * Read directly from the underlying stream, bypassing this buffer entirely. + * + *

This is useful when the caller knows the buffer is empty (e.g., after + * draining via {@link #consume}) and wants to avoid the buffer fill/check overhead. + * + * @param b destination buffer + * @param off offset in destination + * @param len maximum bytes to read + * @return bytes read, or -1 on EOF + * @throws IOException if an I/O error occurs + * @throws IllegalStateException if the buffer is not empty + */ + public int readDirect(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + if (pos < limit) { + throw new IllegalStateException("Buffer not empty: " + (limit - pos) + " bytes remaining"); + } + return in.read(b, off, len); + } + + /** + * Returns the internal buffer array. + * + *

WARNING: The caller must not modify the buffer contents. + * This method is provided for direct buffered read access only. + * + * @return the internal buffer array + */ + public byte[] buffer() { + return buf; + } + + /** + * Returns the current read position in the internal buffer. + * + *

Valid data in the buffer spans from {@code position()} to {@code limit()}. + * + * @return the current read position + */ + public int position() { + return pos; + } + + /** + * Returns the current limit of valid data in the internal buffer. + * + *

Valid data in the buffer spans from {@code position()} to {@code limit()}. + * + * @return the limit of valid data + */ + public int limit() { + return limit; + } + + /** + * Returns the number of bytes currently buffered and available for reading. + * + *

This is equivalent to {@code limit() - position()}. + * + * @return the number of buffered bytes available + */ + public int buffered() { + return limit - pos; + } + + /** + * Advances the internal read position, consuming bytes from the buffer. + * + *

This is used after directly reading from the buffer via {@link #buffer()}. + * + * @param n number of bytes to consume + * @throws IndexOutOfBoundsException if n > buffered() + */ + public void consume(int n) { + if (n < 0 || pos + n > limit) { + throw new IndexOutOfBoundsException("Cannot consume " + n + " bytes, only " + (limit - pos) + " available"); + } + pos += n; + } + + /** + * Reads and discards exactly {@code n} bytes without routing through an {@link OutputStream}. + * + * @param n number of bytes to discard. + * @throws IOException if an I/O error occurs or EOF is reached before {@code n} bytes are discarded. + */ + public void discard(long n) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative: " + n); + } + + long remaining = n; + int buffered = limit - pos; + if (buffered > 0) { + int consumed = (int) Math.min((long) buffered, remaining); + pos += consumed; + remaining -= consumed; + if (remaining == 0) { + return; + } + } + + while (remaining > 0) { + int toRead = (int) Math.min((long) buf.length, remaining); + int read = in.read(buf, 0, toRead); + if (read < 0) { + throw new IOException("Premature EOF while discarding " + remaining + " bytes"); + } + remaining -= read; + } + + pos = 0; + limit = 0; + } + + /** + * Ensures at least {@code n} bytes are available in the buffer. + * + *

If fewer than {@code n} bytes are currently buffered, this method compacts + * the buffer (moves remaining data to the front) and reads more data from the + * underlying stream until at least {@code n} bytes are available or EOF is reached. + * + *

After this method returns true, the caller can safely read {@code n} bytes + * directly from {@link #buffer()} starting at {@link #position()}. + * + * @param n the minimum number of bytes required + * @return true if at least n bytes are now available, false if EOF was reached + * @throws IOException if an I/O error occurs + * @throws IllegalArgumentException if n > buffer size + */ + public boolean ensure(int n) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + if (n > buf.length) { + throw new IllegalArgumentException("Cannot ensure " + n + " bytes, buffer size is " + buf.length); + } + if (n <= 0) { + return true; + } + + int avail = limit - pos; + if (avail >= n) { + return true; + } + + // Compact: move remaining data to front of buffer + if (pos > 0 && avail > 0) { + System.arraycopy(buf, pos, buf, 0, avail); + } + pos = 0; + limit = avail; + + // Fill until we have enough or hit EOF + while (limit < n) { + int read = in.read(buf, limit, buf.length - limit); + if (read < 0) { + return false; // EOF before we could get n bytes + } + limit += read; + } + + return true; + } + + /** + * Reads a line terminated by CRLF or LF into the provided buffer. + * + *

This method is optimized for HTTP header parsing where lines are typically + * short and fit within a single buffer. + * + * @param dest buffer to read line into + * @param maxLength maximum allowed line length + * @return the number of bytes written to dest, or -1 if EOF with no data + * @throws IOException if an I/O error occurs or line exceeds maxLength or dest.length + */ + public int readLine(byte[] dest, int maxLength) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + + int destPos = 0; + + for (;;) { + // Ensure buffer has data + if (pos >= limit && fill() <= 0) { + // EOF - return what we have + return destPos > 0 ? destPos : -1; + } + + // Scan buffer for line terminator - use locals for hot loop + int scanStart = pos; + int maxScan = Math.min(limit, pos + Math.min(maxLength - destPos + 1, dest.length - destPos)); + byte[] localBuf = buf; + + while (pos < maxScan) { + byte b = localBuf[pos]; + if (b == '\r' || b == '\n') { + // Copy scanned bytes to dest + int scannedLen = pos - scanStart; + if (scannedLen > 0) { + System.arraycopy(localBuf, scanStart, dest, destPos, scannedLen); + destPos += scannedLen; + } + pos++; + if (b == '\r') { + // Check for LF after CR + if (pos < limit || fill() > 0) { + if (localBuf[pos] == '\n') { + pos++; + } + } + } + return destPos; + } + pos++; + } + + // Copy scanned bytes to dest + int scannedLen = pos - scanStart; + if (scannedLen > 0) { + System.arraycopy(localBuf, scanStart, dest, destPos, scannedLen); + destPos += scannedLen; + } + + // Check if we hit the length limit without finding terminator + if (destPos > maxLength) { + throw new IOException("Line exceeds maximum length of " + maxLength); + } + if (destPos >= dest.length) { + throw new IOException("Line exceeds buffer size of " + dest.length); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStream.java new file mode 100644 index 0000000000..9bb9b9a49b --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStream.java @@ -0,0 +1,151 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A buffered output stream like {@link java.io.BufferedOutputStream}, but without synchronization. + */ +final class UnsyncBufferedOutputStream extends OutputStream { + private final OutputStream out; + private final byte[] buf; + private int pos; + private boolean closed; + + /** + * Creates a buffered output stream with the specified buffer size. + * + * @param out the underlying output stream + * @param size the buffer size + */ + public UnsyncBufferedOutputStream(OutputStream out, int size) { + if (size <= 0) { + throw new IllegalArgumentException("Buffer size <= 0"); + } + this.out = out; + this.buf = new byte[size]; + } + + private void flushBuffer() throws IOException { + if (pos > 0) { + out.write(buf, 0, pos); + pos = 0; + } + } + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + if (pos >= buf.length) { + flushBuffer(); + } + buf[pos++] = (byte) b; + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } else if (len >= buf.length) { + // If data is larger than buffer, flush and write directly + flushBuffer(); + out.write(b, off, len); + return; + } + + // If data won't fit in remaining buffer, flush first before copying to the buffer. + if (len > buf.length - pos) { + flushBuffer(); + } + + System.arraycopy(b, off, buf, pos, len); + pos += len; + } + + /** + * Writes an ASCII string directly to the buffer. + * Each character is cast to a byte (assumes ASCII/Latin-1 input). + * + * @param s the string to write + * @throws IOException if an I/O error occurs + */ + // we intentionally use the deprecated getBytes(int,int,byte[],int) since it's perfect for copying ascii. + @SuppressWarnings("deprecation") + public void writeAscii(String s) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + int len = s.length(); + if (len == 0) { + return; + } + + // Fast path: string fits in remaining buffer + int available = buf.length - pos; + if (len <= available) { + s.getBytes(0, len, buf, pos); + pos += len; + return; + } + + // Slow path: string spans buffer boundary + writeAsciiSlow(s, len, available); + } + + @SuppressWarnings("deprecation") + private void writeAsciiSlow(String s, int len, int available) throws IOException { + int stringPosition = 0; + int bufLen = buf.length; + + // Work through the string in chunks that fit into the buffer + while (stringPosition < len) { + if (available == 0) { + flushBuffer(); + available = bufLen; + } + + int toCopy = Math.min(available, len - stringPosition); + s.getBytes(stringPosition, stringPosition + toCopy, buf, pos); + pos += toCopy; + stringPosition += toCopy; + available = bufLen - pos; + } + } + + @Override + public void flush() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + flushBuffer(); + out.flush(); + } + + @Override + public void close() throws IOException { + if (!closed) { + try { + flushBuffer(); + } finally { + closed = true; + out.close(); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ByteAllocator.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ByteAllocator.java new file mode 100644 index 0000000000..d4aa524d07 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ByteAllocator.java @@ -0,0 +1,270 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReferenceArray; + +/** + * A lock-free ByteBuffer allocator with optional pooling to reduce GC pressure. + * + *

Pools direct ByteBuffers. Each connection should have its own allocator. + * + *

The pool is split into size classes rather than one mixed stack. This keeps + * frame-sized upload and download buffers reusing other frame-sized buffers instead + * of getting displaced by arbitrary historical sizes. + */ +final class ByteAllocator { + + private final SizeClass[] classes; + private final int maxBufferSize; + private final int maxPoolableSize; + private final int defaultBufferSize; + private H2ConnectionStats stats; + + private static final class SizeClass { + final int bufferSize; + final AtomicReferenceArray stack; + final AtomicInteger top = new AtomicInteger(0); + + SizeClass(int bufferSize, int capacity) { + this.bufferSize = bufferSize; + this.stack = new AtomicReferenceArray<>(capacity); + } + + int capacity() { + return stack.length(); + } + + ByteBuffer tryBorrow() { + while (true) { + int currentTop = top.get(); + if (currentTop == 0) { + return null; + } + int newTop = currentTop - 1; + if (top.compareAndSet(currentTop, newTop)) { + return stack.getAndSet(newTop, null); + } + } + } + + boolean tryRelease(ByteBuffer buffer) { + while (true) { + int currentTop = top.get(); + if (currentTop >= stack.length()) { + return false; + } + if (top.compareAndSet(currentTop, currentTop + 1)) { + stack.set(currentTop, buffer); + return true; + } + } + } + + int size() { + return top.get(); + } + + void clear() { + int n = top.getAndSet(0); + for (int i = 0; i < Math.min(n, stack.length()); i++) { + stack.set(i, null); + } + } + } + + void setStats(H2ConnectionStats stats) { + this.stats = stats; + } + + /** + * @param maxPoolCount maximum buffers to keep in pool + * @param maxBufferSize hard limit on buffer size + * @param maxPoolableSize buffers larger than this are not pooled + * @param defaultBufferSize default size for new buffers when pool is empty + */ + public ByteAllocator(int maxPoolCount, int maxBufferSize, int maxPoolableSize, int defaultBufferSize) { + if (maxPoolCount <= 0) { + throw new IllegalArgumentException("maxPoolCount must be > 0"); + } + if (defaultBufferSize <= 0) { + throw new IllegalArgumentException("defaultBufferSize must be > 0"); + } + if (defaultBufferSize > maxPoolableSize) { + throw new IllegalArgumentException("defaultBufferSize must be <= maxPoolableSize"); + } + if (maxPoolableSize <= 0 || maxPoolableSize > maxBufferSize) { + throw new IllegalArgumentException("maxPoolableSize must be > 0 and <= maxBufferSize"); + } + this.maxBufferSize = maxBufferSize; + this.maxPoolableSize = maxPoolableSize; + this.defaultBufferSize = defaultBufferSize; + this.classes = buildClasses(maxPoolCount, maxPoolableSize, defaultBufferSize); + } + + /** + * Borrow a ByteBuffer from the pool, or allocate a new one. + * + *

Returned buffer is in write mode (position=0, limit=capacity). + * The capacity may be larger than minSize. + * + * @param minSize minimum buffer capacity needed + * @return a ByteBuffer with at least minSize capacity, cleared and ready for writing + */ + public ByteBuffer borrow(int minSize) { + if (minSize <= 0) { + throw new IllegalArgumentException("minSize must be > 0"); + } + if (minSize > maxBufferSize) { + throw new IllegalArgumentException( + "Requested buffer size " + minSize + " exceeds maximum " + maxBufferSize); + } + + if (minSize <= maxPoolableSize) { + int classIndex = findBorrowClassIndex(minSize); + for (int i = classIndex; i < classes.length; i++) { + ByteBuffer buffer = classes[i].tryBorrow(); + if (buffer != null) { + buffer.clear(); + if (stats != null) { + stats.buffersBorrowed.increment(); + stats.buffersReused.increment(); + } + return buffer; + } + } + } + + int size; + if (minSize <= maxPoolableSize) { + size = classes[findBorrowClassIndex(minSize)].bufferSize; + } else { + size = Math.max(minSize, defaultBufferSize); + if (size > maxBufferSize) { + size = maxBufferSize; + } + } + if (stats != null) { + stats.buffersBorrowed.increment(); + stats.buffersAllocated.increment(); + } + return ByteBuffer.allocateDirect(size); + } + + /** + * Return a ByteBuffer to the pool for reuse. + * + * @param buffer the buffer to return (may be null) + */ + public void release(ByteBuffer buffer) { + if (buffer == null) { + return; + } + int classIndex = findReleaseClassIndex(buffer.capacity()); + if (classIndex < 0) { + if (stats != null) { + stats.buffersDropped.increment(); + } + return; + } + + if (!classes[classIndex].tryRelease(buffer)) { + if (stats != null) { + stats.buffersDropped.increment(); + } + } + } + + public int size() { + int size = 0; + for (SizeClass sizeClass : classes) { + size += sizeClass.size(); + } + return size; + } + + public void clear() { + for (SizeClass sizeClass : classes) { + sizeClass.clear(); + } + } + + private int findBorrowClassIndex(int minSize) { + int targetSize = Math.max(minSize, defaultBufferSize); + for (int i = 0; i < classes.length; i++) { + if (classes[i].bufferSize >= targetSize) { + return i; + } + } + return classes.length - 1; + } + + private int findReleaseClassIndex(int capacity) { + for (int i = 0; i < classes.length; i++) { + if (classes[i].bufferSize == capacity) { + return i; + } + } + return -1; + } + + private static SizeClass[] buildClasses(int maxPoolCount, int maxPoolableSize, int defaultBufferSize) { + List sizes = new ArrayList<>(3); + sizes.add(defaultBufferSize); + if (defaultBufferSize < maxPoolableSize) { + int mediumSize = Math.min(maxPoolableSize, Math.max(defaultBufferSize, 16 * 1024)); + if (mediumSize > sizes.get(sizes.size() - 1)) { + sizes.add(mediumSize); + } + if (maxPoolableSize > sizes.get(sizes.size() - 1)) { + sizes.add(maxPoolableSize); + } + } + + int classCount = sizes.size(); + long totalWeight = 0; + long[] weights = new long[classCount]; + for (int i = 0; i < classCount; i++) { + long weight = 1L << i; + weights[i] = weight; + totalWeight += weight; + } + + int[] capacities = new int[classCount]; + int allocated = 0; + if (maxPoolCount >= classCount) { + for (int i = 0; i < classCount; i++) { + capacities[i] = 1; + } + allocated = classCount; + } + for (int i = 0; i < classCount; i++) { + int capacity = (int) (((long) (maxPoolCount - allocated) * weights[i]) / totalWeight); + capacities[i] += capacity; + } + allocated = 0; + for (int capacity : capacities) { + allocated += capacity; + } + for (int i = classCount - 1; allocated < maxPoolCount; i--) { + capacities[i]++; + allocated++; + if (i == 0) { + i = classCount; + } + } + + SizeClass[] classes = new SizeClass[classCount]; + for (int i = 0; i < classCount; i++) { + classes[i] = new SizeClass(sizes.get(i), capacities[i]); + } + return classes; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReader.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReader.java new file mode 100644 index 0000000000..7c013a6180 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReader.java @@ -0,0 +1,167 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.util.function.BooleanSupplier; + +/** + * ByteBuffer-based frame reader that replaces UnsyncBufferedInputStream for H2. + * + *

Reads plaintext from a {@link ReadableByteChannel} (backed by SSLEngine or socket) + * into a single ByteBuffer. The frame codec parses directly from this buffer, + * eliminating intermediate copies. + * + *

The buffer is always in read mode externally. Internally, it compacts and + * fills from the channel when more data is needed. + * + *

Thread safety: single reader thread only (H2Connection reader thread). + * After construction, this object must be the only reader of the transport + * channel. DATA payloads may bypass {@link #buf} via {@link #readIntoDirect}, + * but any extra decrypted/plaintext bytes remain in the transport and are + * drained by subsequent reads through this same reader. Response body channels + * read from queued DATA buffers, not from the transport channel. + */ +final class ChannelFrameReader { + + private final ReadableByteChannel channel; + private final BooleanSupplier transportHasBufferedData; + private ByteBuffer buf; + + ChannelFrameReader(ReadableByteChannel channel, int bufferSize) { + this(channel, bufferSize, () -> false); + } + + ChannelFrameReader(ReadableByteChannel channel, int bufferSize, BooleanSupplier transportHasBufferedData) { + this.channel = channel; + this.transportHasBufferedData = transportHasBufferedData; + this.buf = ByteBuffer.allocate(bufferSize); + this.buf.flip(); // start empty in read mode + } + + /** + * Ensure at least {@code n} bytes are available in the buffer. + * Reads from the channel if needed. + * + * @return true if n bytes are available, false on EOF + */ + boolean ensure(int n) throws IOException { + while (buf.remaining() < n) { + if (buf.hasRemaining()) { + buf.compact(); // switch to write mode, preserving unread data + } else { + buf.clear(); // no unread data to preserve + } + int read; + try { + read = channel.read(buf); + } finally { + buf.flip(); // always restore read mode, even if the read is interrupted + } + if (read < 0) { + return buf.remaining() >= n; + } + } + return true; + } + + /** + * Get the underlying buffer for direct parsing. Buffer is in read mode. + */ + ByteBuffer buffer() { + return buf; + } + + /** + * Number of bytes available without reading from channel. + */ + int buffered() { + return buf.remaining(); + } + + /** + * Returns true if plaintext is buffered in this reader or in the transport below it. + */ + boolean hasBufferedData() { + return buf.hasRemaining() || transportHasBufferedData.getAsBoolean(); + } + + /** + * Read a single byte. + */ + int readByte() throws IOException { + if (!ensure(1)) { + throw new IOException("Unexpected EOF"); + } + return buf.get() & 0xFF; + } + + /** + * Read payload into a byte[] (for control frames like SETTINGS, GOAWAY). + */ + void readInto(byte[] dest, int offset, int length) throws IOException { + while (length > 0) { + if (!buf.hasRemaining()) { + if (!ensure(1)) { + throw new IOException("Unexpected EOF reading payload"); + } + } + int toCopy = Math.min(buf.remaining(), length); + buf.get(dest, offset, toCopy); + offset += toCopy; + length -= toCopy; + } + } + + /** + * Read payload directly into a ByteBuffer (for DATA frames, the zero copy path). + * The destination buffer must be in write mode. + * + *

First drains any buffered data, then reads remaining directly from channel + * into the destination, bypassing our internal buffer entirely. + */ + void readIntoDirect(ByteBuffer dest, int length) throws IOException { + // Drain buffered data first + if (buf.hasRemaining()) { + int toDrain = Math.min(buf.remaining(), length); + int oldLimit = buf.limit(); + buf.limit(buf.position() + toDrain); + dest.put(buf); + buf.limit(oldLimit); + length -= toDrain; + } + + // Read remainder directly from channel into dest, with no intermediate buffer + while (length > 0) { + int oldLimit = dest.limit(); + dest.limit(dest.position() + length); + int n = channel.read(dest); + dest.limit(oldLimit); + if (n < 0) { + throw new IOException("Unexpected EOF reading payload"); + } + length -= n; + } + } + + /** + * Skip bytes (for padding). + */ + void skip(int length) throws IOException { + while (length > 0) { + if (!buf.hasRemaining()) { + if (!ensure(1)) { + throw new IOException("Unexpected EOF skipping bytes"); + } + } + int toSkip = Math.min(buf.remaining(), length); + buf.position(buf.position() + toSkip); + length -= toSkip; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameWriter.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameWriter.java new file mode 100644 index 0000000000..e5cff77fca --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/ChannelFrameWriter.java @@ -0,0 +1,134 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +/** + * ByteBuffer-based frame writer that replaces UnsyncBufferedOutputStream for H2. + * + *

Accumulates frame data into a ByteBuffer and flushes to a + * {@link WritableByteChannel} (backed by SSLEngine or socket). + * Multiple frames are coalesced into a single channel write for + * fewer syscalls. + * + *

Thread safety: single writer thread only (H2Muxer writer thread). + */ +final class ChannelFrameWriter { + + private final WritableByteChannel channel; + private final ByteBuffer buf; + + ChannelFrameWriter(WritableByteChannel channel, int bufferSize) { + this.channel = channel; + // Direct buffer avoids a heap-to-direct copy when passed to SSLEngine.wrap and socket writes. + this.buf = ByteBuffer.allocateDirect(bufferSize); + } + + /** + * Write bytes from a byte array. Flushes if buffer is full. + */ + void write(byte[] src) throws IOException { + write(src, 0, src.length); + } + + /** + * Write bytes from a byte array with offset/length. + */ + void write(byte[] src, int offset, int length) throws IOException { + if (length >= buf.capacity()) { + // Large write: flush buffer, then write directly + flushBuffer(); + ByteBuffer wrapped = ByteBuffer.wrap(src, offset, length); + while (wrapped.hasRemaining()) { + channel.write(wrapped); + } + return; + } + + if (length > buf.remaining()) { + flushBuffer(); + } + buf.put(src, offset, length); + } + + /** + * Write from a ByteBuffer. Zero-copy for DATA frame payloads. + */ + void write(ByteBuffer src) throws IOException { + int length = src.remaining(); + if (length >= buf.capacity()) { + flushBuffer(); + while (src.hasRemaining()) { + channel.write(src); + } + return; + } + + if (length > buf.remaining()) { + flushBuffer(); + } + buf.put(src); + } + + /** + * Write an ASCII string directly without allocation. + */ + @SuppressWarnings("deprecation") + void writeAscii(String s) throws IOException { + int len = s.length(); + if (len == 0) + return; + + if (len > buf.remaining()) { + flushBuffer(); + } + if (len > buf.capacity()) { + // Rare: very long string, write through the existing buffer instead of allocating a byte[]. + int offset = 0; + while (offset < len) { + if (!buf.hasRemaining()) { + flushBuffer(); + } + int chunk = Math.min(buf.remaining(), len - offset); + for (int i = 0; i < chunk; i++) { + buf.put((byte) s.charAt(offset + i)); + } + offset += chunk; + } + return; + } + if (buf.hasArray()) { + // Heap buffer: write directly into backing array + s.getBytes(0, len, buf.array(), buf.arrayOffset() + buf.position()); + buf.position(buf.position() + len); + } else { + // Direct buffer: byte-by-byte put (rare path, only used for GOAWAY debug strings) + for (int i = 0; i < len; i++) { + buf.put((byte) s.charAt(i)); + } + } + } + + /** + * Flush buffered data to the channel. + */ + void flush() throws IOException { + flushBuffer(); + } + + private void flushBuffer() throws IOException { + if (buf.position() > 0) { + buf.flip(); + while (buf.hasRemaining()) { + channel.write(buf); + } + buf.clear(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/DynamicTable.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/DynamicTable.java new file mode 100644 index 0000000000..a84998d995 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/DynamicTable.java @@ -0,0 +1,232 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.util.ArrayList; + +/** + * HPACK dynamic table implementation from RFC 7541 Section 2.3.2. + * + *

The dynamic table is a FIFO queue of header field entries. New entries + * are added at index 62 (lowest dynamic index), and older entries are evicted + * first when the table size exceeds the maximum. + * + *

Dynamic table indices start at 62 (after the 61 static table entries). + * Index 62 is the most recently added entry. + * + *

Entries are stored as interleaved name/value pairs. We use an ArrayList + * with reverse indexing: new entries append to the end (O(1)), and index 62 + * maps to the last pair. Eviction removes from the front. + * + *

Header names must be lowercase as required by HTTP/2 (RFC 9113 Section 8.2.1). + */ +final class DynamicTable { + + /** + * Each entry has 32 bytes of overhead per RFC 7541 Section 4.1. + */ + private static final int ENTRY_OVERHEAD = 32; + + // Interleaved storage: [name0, value0, name1, value1, ...] + // Newest entries at the END (reverse of logical HPACK order) + private final ArrayList entries = new ArrayList<>(); + private int numEntries = 0; + private int currentSize = 0; + private int maxSize; + + /** + * Create a dynamic table with the given maximum size. + * + * @param maxSize maximum table size in bytes + */ + DynamicTable(int maxSize) { + this.maxSize = maxSize; + } + + /** + * Get the current number of entries in the table. + * + * @return entry count + */ + int length() { + return numEntries; + } + + /** + * Get the current size of the table in bytes. + * + * @return current size + */ + int size() { + return currentSize; + } + + /** + * Get the maximum size of the table in bytes. + * + * @return maximum size + */ + int maxSize() { + return maxSize; + } + + /** + * Set a new maximum table size. + * + *

If the new size is smaller than current size, entries are evicted. + * + * @param newMaxSize new maximum size in bytes + */ + void setMaxSize(int newMaxSize) { + if (newMaxSize == maxSize) { + return; + } + this.maxSize = newMaxSize; + evictToSize(newMaxSize); + } + + /** + * Add a new entry to the dynamic table. + * + *

The entry is added at index 62 (first dynamic index). + * Existing entries shift to higher indices. + * + * @param name header name + * @param value header value + */ + void add(String name, String value) { + int entrySize = entrySize(name, value); + + // RFC 7541 Section 4.4: "an attempt to add an entry larger than the maximum size + // causes the table to be emptied of all existing entries and results in an empty table" + if (entrySize > maxSize) { + clear(); + return; + } + + // Evict entries until there's room + evictToSize(maxSize - entrySize); + + // Append to end (newest = highest array index, but lowest HPACK index) + entries.add(name); + entries.add(value); + currentSize += entrySize; + numEntries++; + } + + /** + * Get header name at the given index. + * + * @param index dynamic table index (62 + offset) + * @return header name + * @throws IndexOutOfBoundsException if index is out of range + */ + String getName(int index) { + return entries.get(toArrayIndex(index)); + } + + /** + * Get header value at the given index. + * + * @param index dynamic table index (62 + offset) + * @return header value + * @throws IndexOutOfBoundsException if index is out of range + */ + String getValue(int index) { + return entries.get(toArrayIndex(index) + 1); + } + + /** + * Convert HPACK index to array index. + * HPACK index 62 = newest entry = last pair in array. + */ + private int toArrayIndex(int hpackIndex) { + int offset = hpackIndex - StaticTable.SIZE - 1; + if (offset < 0 || offset >= numEntries) { + throw new IndexOutOfBoundsException("Dynamic table index out of range: " + + hpackIndex + " (table has " + numEntries + " entries)"); + } + // Reverse: offset 0 -> last pair, offset 1 -> second-to-last, etc. + return entries.size() - 2 - (offset * 2); + } + + /** + * Convert an array index to an HPACK dynamic table index. + */ + private int toHpackIndex(int arrayIndex) { + return StaticTable.SIZE + 1 + (entries.size() - 2 - arrayIndex) / 2; + } + + /** + * Find the index of a full match (name + value) in the dynamic table. + * + * @param name header name + * @param value header value + * @return dynamic table index (62+) if found, -1 otherwise + */ + int findFullMatch(String name, String value) { + // Search from newest (end) to oldest (start) + for (int i = entries.size() - 2; i >= 0; i -= 2) { + if (entries.get(i).equals(name) && entries.get(i + 1).equals(value)) { + return toHpackIndex(i); + } + } + return -1; + } + + /** + * Find the index of a name-only match in the dynamic table. + * + * @param name header name + * @return dynamic table index (62+) if found, -1 otherwise + */ + int findNameMatch(String name) { + for (int i = entries.size() - 2; i >= 0; i -= 2) { + if (entries.get(i).equals(name)) { + return toHpackIndex(i); + } + } + return -1; + } + + /** + * Clear all entries from the table. + */ + void clear() { + entries.clear(); + currentSize = 0; + numEntries = 0; + } + + /** + * Calculate the size of an entry per RFC 7541 Section 4.1. + * Size = length(name) + length(value) + 32 + * + * @param name header name + * @param value header value + * @return entry size in bytes + */ + static int entrySize(String name, String value) { + return name.length() + value.length() + ENTRY_OVERHEAD; + } + + private void evictToSize(int targetSize) { + int removeCount = 0; + int removedSize = 0; + + // Efficiently resize in one-shot. + while (currentSize - removedSize > targetSize && removeCount < entries.size()) { + removedSize += entrySize(entries.get(removeCount), entries.get(removeCount + 1)); + removeCount += 2; + } + + if (removeCount > 0) { + entries.subList(0, removeCount).clear(); + currentSize -= removedSize; + numEntries -= removeCount / 2; + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/FlowControlWindow.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/FlowControlWindow.java new file mode 100644 index 0000000000..16e4fb781b --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/FlowControlWindow.java @@ -0,0 +1,137 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * HTTP/2 flow control window. + * + *

Fast path uses an {@link AtomicLong} CAS loop with no lock. Under typical load + * (window available, no waiters) acquires and releases are lock-free. The lock is only + * acquired on the slow path when a caller has to wait for window. + * + *

Uses ReentrantLock instead of synchronized to avoid virtual thread pinning on the slow path. + */ +final class FlowControlWindow { + + // Poll interval for timeout checking (avoids ScheduledThreadPoolExecutor contention) + private static final long POLL_INTERVAL_NS = TimeUnit.MILLISECONDS.toNanos(10); + + private final ReentrantLock lock = new ReentrantLock(); + private final Condition available = lock.newCondition(); + private final AtomicLong window; + + FlowControlWindow(int initialWindow) { + this.window = new AtomicLong(initialWindow); + } + + /** + * Try to acquire up to the requested bytes from the window without blocking. + * + * @return number of bytes acquired (0 if window is empty) + */ + int tryAcquireNonBlocking(int maxBytes) { + while (true) { + long current = window.get(); + if (current <= 0) { + return 0; + } + int acquired = (int) Math.min(current, maxBytes); + if (window.compareAndSet(current, current - acquired)) { + return acquired; + } + // CAS lost to another acquirer or a release; retry. + } + } + + /** + * Try to acquire up to the requested bytes, waiting if the window is empty. + * + * @return number of bytes acquired (0 if timeout expired) + */ + int tryAcquireUpTo(int maxBytes, long timeoutMs) throws InterruptedException { + // Fast path: lock-free CAS + int acquired = tryAcquireNonBlocking(maxBytes); + if (acquired > 0) { + return acquired; + } + + // Slow path: window empty, take the lock and wait on condition + lock.lock(); + try { + long deadlineNs = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs); + while (true) { + acquired = tryAcquireNonBlocking(maxBytes); + if (acquired > 0) { + return acquired; + } + long remainingNs = deadlineNs - System.nanoTime(); + if (remainingNs <= 0) { + return 0; + } + // Return value intentionally ignored: the loop re-checks the window via + // tryAcquireNonBlocking and recomputes the remaining time from deadlineNs, so the + // nanos-left hint from awaitNanos adds nothing. A short POLL_INTERVAL_NS cap bounds + // the wait so a missed release signal is still picked up on the next tick. + long ignored = available.awaitNanos(Math.min(remainingNs, POLL_INTERVAL_NS)); + } + } finally { + lock.unlock(); + } + } + + /** + * Release bytes back to the window. + */ + void release(int bytes) { + if (bytes <= 0) { + return; + } + window.addAndGet(bytes); + // Signal condition so any slow-path waiters wake up and re-try the fast path. + // Uses tryLock to avoid pinning the writer if a VT is currently holding the lock; + // the VT will re-check after awaitNanos returns so a missed signal is caught at the + // next POLL_INTERVAL_NS tick. + if (lock.tryLock()) { + try { + available.signalAll(); + } finally { + lock.unlock(); + } + } + } + + /** + * Get the current available window size. + */ + int available() { + long cur = window.get(); + return (int) Math.max(Integer.MIN_VALUE, Math.min(cur, Integer.MAX_VALUE)); + } + + /** + * Adjust the window size (e.g., when SETTINGS changes initial window). + * + *

This can increase or decrease the window. If decreasing, the window + * may become negative (valid in HTTP/2), and writers will block until + * WINDOW_UPDATE frames restore capacity. + */ + void adjust(int delta) { + window.addAndGet(delta); + if (delta > 0) { + lock.lock(); + try { + available.signalAll(); + } finally { + lock.unlock(); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Connection.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Connection.java new file mode 100644 index 0000000000..db57d233ab --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Connection.java @@ -0,0 +1,896 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_HEADER_TABLE_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_INITIAL_WINDOW_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_MAX_CONCURRENT_STREAMS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_MAX_FRAME_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_COMPRESSION_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_ENHANCE_YOUR_CALM; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_FLOW_CONTROL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_NO_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_PROTOCOL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_SETTINGS_TIMEOUT; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_ACK; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_END_HEADERS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_END_STREAM; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_PADDED; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_DATA; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_GOAWAY; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_HEADERS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PING; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PUSH_PROMISE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_RST_STREAM; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_SETTINGS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_WINDOW_UPDATE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.MAX_MAX_FRAME_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.MIN_MAX_FRAME_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_ENABLE_PUSH; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_HEADER_TABLE_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_INITIAL_WINDOW_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_MAX_CONCURRENT_STREAMS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_MAX_FRAME_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.SETTINGS_MAX_HEADER_LIST_SIZE; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; +import javax.net.ssl.SSLSession; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.connection.ConnectionTransport; +import software.amazon.smithy.java.http.client.connection.MultiplexedHttpConnection; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.logging.InternalLogger; + +/** + * HTTP/2 connection implementation with full stream multiplexing. + * + *

This implementation manages an HTTP/2 connection over a single TCP socket + * with support for multiple concurrent streams. A background reader thread + * dispatches incoming frames to the multiplexer. + * + *

Connection Lifecycle

+ *
    + *
  1. Constructor sends connection preface and SETTINGS
  2. + *
  3. Waits for server SETTINGS and sends ACK
  4. + *
  5. Starts background reader thread for frame dispatch
  6. + *
  7. {@link #newExchange} creates exchanges for requests
  8. + *
  9. {@link #close} sends GOAWAY and closes socket
  10. + *
+ * + *

Thread Safety

+ *

This class is thread-safe. Multiple virtual threads can create + * concurrent exchanges on the same connection. Frame writes are serialized + * via the muxer's writer thread, and frame reads are handled by a + * dedicated reader thread. + */ +public final class H2Connection implements MultiplexedHttpConnection, H2Muxer.ConnectionCallback { + private enum State { + CONNECTED, + SHUTTING_DOWN, + CLOSED + } + + private static final InternalLogger LOGGER = InternalLogger.getLogger(H2Connection.class); + private static final int SETTINGS_TIMEOUT_MS = 10_000; + private static final int GRACEFUL_SHUTDOWN_MS = 1000; + + private final ConnectionTransport transport; + private final Route route; + private final H2FrameCodec frameCodec; + private final H2Muxer muxer; + private final H2ConnectionStats stats = new H2ConnectionStats(); + private final HpackDecoder hpackDecoder; + private final Thread readerThread; + private final long readTimeoutMs; + private final long writeTimeoutMs; + private final int maxFrameSize; + + // Connection settings from peer + private volatile int remoteMaxFrameSize = DEFAULT_MAX_FRAME_SIZE; + private volatile int remoteInitialWindowSize = DEFAULT_INITIAL_WINDOW_SIZE; + private volatile int remoteMaxConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS; + private volatile int remoteMaxHeaderListSize = Integer.MAX_VALUE; + + // Connection receive window. Debited by reader thread, credited by application threads as data is consumed. + private final ReentrantLock connectionRecvWindowLock = new ReentrantLock(); + private int connectionRecvWindow; + private int pendingConnectionWindowUpdate; + private final int initialWindowSize; + + // Connection state (AtomicReference for safe concurrent close) + private final AtomicReference state = new AtomicReference<>(State.CONNECTED); + private volatile boolean active = true; + private volatile boolean goawayReceived = false; + private volatile Throwable readerError; + // Track last activity tick for idle timeout (tick = TIMEOUT_POLL_INTERVAL_MS, ~100ms resolution) + private volatile int lastActivityTick; + + /** + * Create an HTTP/2 connection from a connected socket. + * + * @param route the route for this connection + * @param readTimeout read timeout duration + * @param writeTimeout write timeout duration + * @param initialWindowSize initial flow control window size in bytes + * @param maxFrameSize maximum frame size to advertise to server + * @param bufferSize I/O buffer size in bytes + */ + public H2Connection( + ConnectionTransport transport, + Route route, + Duration readTimeout, + Duration writeTimeout, + int initialWindowSize, + int maxFrameSize, + int bufferSize + ) throws IOException { + this.transport = transport; + this.maxFrameSize = maxFrameSize; + var channelReader = new ChannelFrameReader(transport.readableChannel(), bufferSize, transport::hasBufferedData); + var channelWriter = new ChannelFrameWriter(transport.writableChannel(), bufferSize); + this.route = route; + this.readTimeoutMs = readTimeout.toMillis(); + this.writeTimeoutMs = writeTimeout.toMillis(); + this.frameCodec = new H2FrameCodec(channelReader, channelWriter, maxFrameSize); + this.hpackDecoder = new HpackDecoder(DEFAULT_HEADER_TABLE_SIZE); + this.initialWindowSize = initialWindowSize; + this.connectionRecvWindow = initialWindowSize; + + // Create muxer before connection preface (applyRemoteSettings needs it) + this.muxer = new H2Muxer(this, + frameCodec, + DEFAULT_HEADER_TABLE_SIZE, + "h2-writer-" + route.host(), + initialWindowSize); + this.muxer.setStats(stats); + + // Perform connection preface + try { + sendConnectionPreface(); + receiveServerPreface(); + // Try to receive initial connection WINDOW_UPDATE (server often sends this right after SETTINGS) + receiveInitialWindowUpdate(); + } catch (IOException e) { + close(); + throw new IOException("HTTP/2 connection preface failed", e); + } + + // Start background reader thread + this.readerThread = Thread.ofVirtual() + .name("h2-reader-" + route.host()) + .start(this::readerLoop); + } + + /** + * Set a callback to be invoked when an H2 stream is released. + * Used by the connection manager to signal waiters when capacity becomes available. + */ + public void setStreamReleaseCallback(Runnable callback) { + muxer.setStreamReleaseCallback(callback); + } + + // ==================== ConnectionCallback implementation ==================== + + @Override + public boolean isAcceptingStreams() { + return state.get() == State.CONNECTED && !goawayReceived; + } + + @Override + public int getRemoteMaxHeaderListSize() { + return remoteMaxHeaderListSize; + } + + // ==================== Reader Thread ==================== + + // Track last stream for batched signaling (stream-switch detection). + private H2Exchange lastDataExchange; + + private void readerLoop() { + try { + while (state.get() != State.CLOSED) { + int type = frameCodec.nextFrame(); + if (type < 0) { + break; // EOF + } + + // Update last activity tick on every frame received (cheap volatile write vs syscall) + lastActivityTick = muxer.currentTimeoutTick(); + + if (type == FRAME_TYPE_DATA) { + handleDataFrame(); + } else { + // Non-DATA frame: flush any pending data stream before processing + if (lastDataExchange != null) { + lastDataExchange.signalDataAvailable(); + lastDataExchange = null; + } + handleNonDataFrame(); + } + } + } catch (IOException e) { + if (state.get() == State.CONNECTED) { + readerError = e; + active = false; + LOGGER.debug("Reader thread error for {}: {}", route, e.getMessage()); + } + } finally { + // Flush any pending stream before shutdown + if (lastDataExchange != null) { + lastDataExchange.signalDataAvailable(); + lastDataExchange = null; + } + muxer.shutdownNow(); + muxer.onConnectionClosing(readerError); + state.set(State.CLOSED); + try { + transport.close(); + } catch (IOException ignored) {} + } + } + + private void handleDataFrame() throws IOException { + int streamId = frameCodec.frameStreamId(); + int payloadLength = frameCodec.framePayloadLength(); + boolean endStream = frameCodec.hasFrameFlag(FLAG_END_STREAM); + boolean padded = frameCodec.hasFrameFlag(FLAG_PADDED); + + if (streamId == 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "DATA frame must have non-zero stream ID"); + } + + H2Exchange exchange = muxer.getExchange(streamId); + + // Stream switch detection: flush the previous stream if we're switching. + if (lastDataExchange != null && lastDataExchange != exchange) { + lastDataExchange.signalDataAvailable(); + } + + int padLength = 0; + int dataLength = payloadLength; + if (padded) { + if (payloadLength < 1) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "Padded DATA frame too short"); + } + padLength = frameCodec.readByte(); + dataLength = payloadLength - 1 - padLength; + if (dataLength < 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "Pad length " + padLength + " exceeds payload"); + } + } + + if (exchange != null) { + if (dataLength > 0) { + ByteBuffer buffer = muxer.borrowBuffer(dataLength); + frameCodec.readPayloadDirect(buffer, dataLength); + buffer.flip(); + boolean moreDataBuffered = frameCodec.hasBufferedData(); + debitConnectionRecvWindow(payloadLength); + exchange.enqueueData(buffer, endStream, moreDataBuffered, payloadLength); + + stats.dataFramesRead.increment(); + stats.dataBytesRead.add(dataLength); + + if (endStream) { + stats.signalsSent.increment(); + lastDataExchange = null; + } else if (moreDataBuffered) { + lastDataExchange = exchange; + stats.signalsDeferred.increment(); + } else { + lastDataExchange = null; + // signal happens via enqueueData when !moreDataBuffered + stats.signalsSent.increment(); + } + } else if (endStream) { + if (payloadLength > 0) { + debitConnectionRecvWindow(payloadLength); + exchange.releaseDiscardedData(payloadLength); + } + exchange.enqueueData(null, true, false, 0); + lastDataExchange = null; + } else if (payloadLength > 0) { + debitConnectionRecvWindow(payloadLength); + exchange.releaseDiscardedData(payloadLength); + } + } else { + if (payloadLength > 0) { + if (dataLength > 0) { + frameCodec.skipBytes(dataLength); + } + debitConnectionRecvWindow(payloadLength); + releaseConnectionReceiveWindow(payloadLength); + } + LOGGER.trace("Ignoring DATA frame for closed stream {}", streamId); + // Clear tracker if buffer empty (even for unknown streams) + if (!frameCodec.hasBufferedData()) { + lastDataExchange = null; + } + } + + if (padLength > 0) { + frameCodec.skipBytes(padLength); + } + } + + private void handleNonDataFrame() throws IOException { + int type = frameCodec.frameType(); + int streamId = frameCodec.frameStreamId(); + int length = frameCodec.framePayloadLength(); + + // Fast path: handle small control frames (WINDOW_UPDATE, RST_STREAM) without buffer allocation. + // These frames are always exactly 4 bytes and very common during flow control. + if (type == FRAME_TYPE_WINDOW_UPDATE) { + int increment = frameCodec.readAndParseWindowUpdate(); + if (streamId == 0) { + stats.connWindowUpdatesReceived.increment(); + stats.connWindowBytesReceived.add(increment); + muxer.releaseConnectionWindow(increment); + } else { + H2Exchange exchange = muxer.getExchange(streamId); + if (exchange != null) { + exchange.updateStreamSendWindow(increment); + } + // Ignore WINDOW_UPDATE for unknown streams (closed streams, etc.) + } + return; + } + + if (type == FRAME_TYPE_RST_STREAM && streamId != 0) { + int errorCode = frameCodec.readAndParseRstStream(); + H2Exchange exchange = muxer.getExchange(streamId); + if (exchange != null) { + H2Exception error = new H2Exception(errorCode, + streamId, + "Stream reset by server: " + H2Constants.errorCodeName(errorCode)); + exchange.signalStreamError(error); + } + // Ignore RST_STREAM for unknown streams + return; + } + + // Standard path: read payload into byte[] for control frame parsing + byte[] payload; + if (length == 0) { + payload = H2Constants.EMPTY_BYTES; + } else { + payload = muxer.borrowByteArray(length); + frameCodec.readPayloadInto(payload, 0, length); + } + + try { + if (streamId == 0) { + handleConnectionFrame(type, payload, length); + } else { + // Always normalize HEADERS through readHeaderBlock so padding, priority, and + // PUSH_PROMISE promised-stream-id are stripped before the header block reaches + // HPACK. Otherwise those bytes corrupt HPACK state and tear the connection. + // Also enforces a running cap on accumulated CONTINUATION growth. + byte[] headerPayload = payload; + int headerLength = length; + if (type == FRAME_TYPE_HEADERS) { + // Capture END_HEADERS before readHeaderBlock, which may consume CONTINUATION frames + // and leave the flag reflecting the final CONTINUATION rather than the initial HEADERS. + boolean initialEndHeaders = frameCodec.hasFrameFlag(FLAG_END_HEADERS); + headerPayload = frameCodec.readHeaderBlock( + streamId, + payload, + length, + H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + // Single-frame path returns an exact-length array; the CONTINUATION path returns the + // accumulation buffer's backing array, whose length is its capacity, not the data size. + headerLength = initialEndHeaders + ? headerPayload.length + : frameCodec.headerBlockSize(); + payload = null; + } + + H2Exchange exchange = muxer.getExchange(streamId); + if (exchange != null) { + dispatchStreamFrame(exchange, type, streamId, headerPayload, headerLength); + } else { + handleFrameForUnknownStream(type, streamId, headerPayload, headerLength); + } + } + } finally { + // Non-DATA payloads are plain byte[] from borrowByteArray, not pooled, so no return needed + } + } + + private void handleFrameForUnknownStream(int type, int streamId, byte[] payload, int length) throws IOException { + // Note: DATA frames for unknown streams are handled in handleDataFrame(), not here. + if (type == FRAME_TYPE_HEADERS) { + // Must decode headers to maintain HPACK state, even for unknown streams + if (payload != null && length > 0) { + decodeHeaders(payload, length); + } + LOGGER.trace("Ignoring HEADERS frame for unknown stream {}", streamId); + } + } + + private void dispatchStreamFrame(H2Exchange exchange, int type, int streamId, byte[] payload, int length) + throws IOException { + // Note: WINDOW_UPDATE and RST_STREAM are handled in handleNonDataFrame fast path + switch (type) { + case FRAME_TYPE_HEADERS -> { + List decoded; + if (payload != null && length > 0) { + decoded = decodeHeaders(payload, length); + } else { + decoded = List.of(); + } + boolean endStream = frameCodec.hasFrameFlag(FLAG_END_STREAM); + exchange.deliverHeaders(decoded, endStream); + } + case FRAME_TYPE_PUSH_PROMISE -> { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Received PUSH_PROMISE but server push is disabled"); + } + default -> { + } + } + } + + private void handleConnectionFrame(int type, byte[] payload, int length) throws IOException { + // Note: WINDOW_UPDATE is handled in handleNonDataFrame fast path + switch (type) { + case FRAME_TYPE_SETTINGS -> { + if (!frameCodec.hasFrameFlag(FLAG_ACK)) { + int[] settings = frameCodec.parseSettings(payload, length); + applyRemoteSettings(settings); + muxer.queueControlFrame(0, + H2Muxer.ControlFrameType.SETTINGS_ACK, + null, + writeTimeoutMs); + } + } + case FRAME_TYPE_PING -> { + if (!frameCodec.hasFrameFlag(FLAG_ACK)) { + // Copy payload for async write (payload may be pooled buffer) + byte[] pingData = new byte[8]; + System.arraycopy(payload, 0, pingData, 0, 8); + muxer.queueControlFrame(0, + H2Muxer.ControlFrameType.PING, + pingData, + writeTimeoutMs); + } + } + case FRAME_TYPE_GOAWAY -> { + int[] goaway = frameCodec.parseGoaway(payload, length); + handleGoaway(goaway[0], goaway[1]); + } + default -> { + } + } + } + + // ==================== Connection Preface ==================== + + private void sendConnectionPreface() throws IOException { + frameCodec.writeConnectionPreface(); + frameCodec.writeSettings( + SETTINGS_MAX_CONCURRENT_STREAMS, + 100, + SETTINGS_INITIAL_WINDOW_SIZE, + initialWindowSize, + SETTINGS_MAX_FRAME_SIZE, + maxFrameSize, + SETTINGS_ENABLE_PUSH, + 0); + frameCodec.flush(); + + // If using a larger window than the RFC default, send a connection-level WINDOW_UPDATE + // to expand the connection receive window immediately + if (initialWindowSize > DEFAULT_INITIAL_WINDOW_SIZE) { + int increment = initialWindowSize - DEFAULT_INITIAL_WINDOW_SIZE; + frameCodec.writeWindowUpdate(0, increment); + frameCodec.flush(); + } + } + + private void receiveServerPreface() throws IOException { + int originalTimeout = transport.getReadTimeout(); + try { + transport.setReadTimeout(SETTINGS_TIMEOUT_MS); + + int type; + try { + type = frameCodec.nextFrame(); + } catch (SocketTimeoutException e) { + throw new H2Exception(ERROR_SETTINGS_TIMEOUT, "Timeout waiting for server SETTINGS frame"); + } + + if (type < 0) { + throw new IOException("Connection closed before receiving server SETTINGS"); + } + if (type != FRAME_TYPE_SETTINGS) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Expected SETTINGS frame, got " + H2Constants.frameTypeName(type)); + } + if (frameCodec.hasFrameFlag(FLAG_ACK)) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "First SETTINGS frame must not be ACK"); + } + + // Read and parse settings payload + int length = frameCodec.framePayloadLength(); + byte[] payload; + if (length == 0) { + payload = H2Constants.EMPTY_BYTES; + } else { + payload = new byte[length]; + frameCodec.readPayloadInto(payload, 0, length); + } + int[] settings = frameCodec.parseSettings(payload, length); + applyRemoteSettings(settings); + + frameCodec.writeSettingsAck(); + frameCodec.flush(); + } finally { + transport.setReadTimeout(originalTimeout); + } + } + + /** + * Try to receive the initial connection-level WINDOW_UPDATE that servers typically send + * right after SETTINGS to expand the connection flow control window. + * Uses a short timeout - if no frame arrives quickly, we proceed anyway. + * + *

At this point in the handshake, the only valid frames the server can send are: + *

    + *
  • WINDOW_UPDATE - what we're looking for, apply it
  • + *
  • SETTINGS ACK - acknowledgment of our SETTINGS, safe to ignore
  • + *
+ * Any other frame type is a protocol error. + */ + private void receiveInitialWindowUpdate() throws IOException { + int originalTimeout = transport.getReadTimeout(); + try { + transport.setReadTimeout(50); // Short timeout - don't block long if server doesn't send one + int type = frameCodec.nextFrame(); + switch (type) { + case -1: + break; + case FRAME_TYPE_SETTINGS: + if (!frameCodec.hasFrameFlag(FLAG_ACK)) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Unexpected non-ACK SETTINGS during handshake"); + } + break; + case FRAME_TYPE_WINDOW_UPDATE: + if (frameCodec.frameStreamId() == 0) { + int increment = frameCodec.readAndParseWindowUpdate(); + muxer.releaseConnectionWindow(increment); + } else { + int sid = frameCodec.frameStreamId(); + frameCodec.skipBytes(frameCodec.framePayloadLength()); + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Stream-level WINDOW_UPDATE during handshake (stream " + sid + ")"); + } + break; + default: + throw new H2Exception( + ERROR_PROTOCOL_ERROR, + "Unexpected frame during handshake: " + H2Constants.frameTypeName(type)); + } + } catch (SocketTimeoutException e) { + // No initial WINDOW_UPDATE - that's fine, proceed with default window + } finally { + transport.setReadTimeout(originalTimeout); + } + } + + private void applyRemoteSettings(int[] settings) throws IOException { + for (int i = 0; i < settings.length; i += 2) { + int id = settings[i]; + int value = settings[i + 1]; + + switch (id) { + case SETTINGS_HEADER_TABLE_SIZE: + muxer.setMaxTableSize(value); + break; + case SETTINGS_ENABLE_PUSH: + if (value != 0 && value != 1) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "Invalid SETTINGS_ENABLE_PUSH: " + value); + } + break; + case SETTINGS_MAX_CONCURRENT_STREAMS: + remoteMaxConcurrentStreams = value; + muxer.onSettingsReceived(value, remoteInitialWindowSize, remoteMaxFrameSize); + break; + case SETTINGS_INITIAL_WINDOW_SIZE: + if (value < 0) { + throw new H2Exception(ERROR_FLOW_CONTROL_ERROR, + "Invalid INITIAL_WINDOW_SIZE: " + (value & 0xFFFFFFFFL)); + } + remoteInitialWindowSize = value; + muxer.onSettingsReceived(remoteMaxConcurrentStreams, value, remoteMaxFrameSize); + break; + case SETTINGS_MAX_FRAME_SIZE: + if (value < MIN_MAX_FRAME_SIZE || value > MAX_MAX_FRAME_SIZE) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "Invalid MAX_FRAME_SIZE: " + value); + } + remoteMaxFrameSize = value; + muxer.onSettingsReceived(remoteMaxConcurrentStreams, remoteInitialWindowSize, value); + break; + case SETTINGS_MAX_HEADER_LIST_SIZE: + remoteMaxHeaderListSize = value; + break; + default: + break; + } + } + } + + // ==================== Exchange Creation ==================== + + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + if (state.get() != State.CONNECTED) { + throw new IOException("Connection is not in CONNECTED state: " + state.get()); + } + + request = options.applyExpectContinue(request); + + // Update last activity tick when creating a new exchange + lastActivityTick = muxer.currentTimeoutTick(); + + H2Exchange exchange = muxer.newExchange(request, readTimeoutMs, writeTimeoutMs); + + try { + boolean hasBody = request.body() != null && request.body().contentLength() != 0; + boolean endStream = !hasBody; + + if (!muxer.submitHeaders(request, exchange, endStream, writeTimeoutMs)) { + muxer.releaseStreamSlot(); + throw new IOException("Connection not accepting new streams"); + } + + // Block until headers are encoded and written + // Stream ID is set on the exchange by the muxer before signaling + exchange.awaitWriteCompletion(); + + IOException writeErr = muxer.getWriteError(); + if (writeErr != null) { + int streamId = exchange.getStreamId(); + if (streamId > 0) { + muxer.releaseStream(streamId); + } + throw writeErr; + } + + return exchange; + + } catch (IOException e) { + int streamId = exchange.getStreamId(); + if (streamId > 0) { + muxer.releaseStream(streamId); + } + throw e; + } + } + + // ==================== Connection State ==================== + + public int getActiveStreamCount() { + return muxer.getActiveStreamCount(); + } + + /** + * Get internal diagnostic stats for this connection. + * Package-private, for tests and benchmarks only. + */ + H2ConnectionStats getStats() { + return stats; + } + + /** + * Check if this connection can accept more streams. + * + *

This is the primary check used in the connection acquisition hot path. It combines active state, write error, + * and muxer capacity checks to minimize redundant checks. + */ + public boolean canAcceptMoreStreams() { + return active && muxer.getWriteError() == null && muxer.canAcceptMoreStreams(); + } + + /** + * Get the active stream count if this connection can accept more streams, or -1 if not. + * Combines the availability check with getting the count to avoid redundant atomic reads + * in the connection acquisition hot path. + */ + public int getActiveStreamCountIfAccepting() { + if (!active || muxer.getWriteError() != null) { + return -1; + } + return muxer.getActiveStreamCountIfAccepting(); + } + + /** + * Get the time in nanoseconds since the last activity on this connection. + * + *

If there are active streams, returns 0 (not idle). + * Otherwise, returns the time since the last frame was received or exchange was created. + * + *

Note: Resolution is ~100ms (tick-based) to avoid System.nanoTime() syscalls on hot path. + * + * @return idle time in nanoseconds, or 0 if there are active streams + */ + public long getIdleTimeNanos() { + if (getActiveStreamCount() > 0) { + return 0; // Not idle if there are active streams + } + int idleTicks = muxer.currentTimeoutTick() - lastActivityTick; + // Convert ticks to nanoseconds: ticks * ms_per_tick * nanos_per_ms + return (long) idleTicks * H2Muxer.TIMEOUT_POLL_INTERVAL_MS * 1_000_000L; + } + + @Override + public HttpVersion httpVersion() { + return HttpVersion.HTTP_2; + } + + @Override + public boolean isActive() { + return active && muxer.getWriteError() == null; + } + + @Override + public boolean validateForReuse() { + // Fast path: 'active' is set to false by reader thread on socket issues, + // so if it's false, no need for expensive socket checks. + if (!active) { + return false; + } + + // Check for write errors + IOException writeErr = muxer.getWriteError(); + if (writeErr != null) { + LOGGER.debug("Connection to {} has write error", route); + active = false; + state.set(State.CLOSED); + return false; + } + + // Socket checks skipped here - reader thread sets active=false on socket issues. + return true; + } + + @Override + public Route route() { + return route; + } + + @Override + public SSLSession sslSession() { + return transport.sslSession(); + } + + @Override + public String negotiatedProtocol() { + String protocol = transport.negotiatedProtocol(); + return protocol != null ? protocol : "h2"; + } + + @Override + public void close() throws IOException { + // Check if it's already shutting down or closed + if (!state.compareAndSet(State.CONNECTED, State.SHUTTING_DOWN)) { + return; + } + + active = false; + + // Queue the control frame to shutdown, but use a short timeout + var payload = new Object[] {muxer.getLastAllocatedStreamId(), ERROR_NO_ERROR, null}; + muxer.queueControlFrame(0, H2Muxer.ControlFrameType.GOAWAY, payload, 100); + + muxer.close(); + muxer.closeExchanges(Duration.ofMillis(GRACEFUL_SHUTDOWN_MS)); + state.set(State.CLOSED); + transport.close(); + + try { + readerThread.join(100); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + } + + // Called only from reader thread - no synchronization needed + List decodeHeaders(byte[] headerBlock, int length) throws IOException { + int maxHeaderListSize = H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE; + if (length > maxHeaderListSize) { + throw new H2Exception(ERROR_ENHANCE_YOUR_CALM, + "Header block size " + length + " exceeds limit " + maxHeaderListSize); + } + + List headers; + try { + headers = hpackDecoder.decode(headerBlock, 0, length); + } catch (IOException e) { + active = false; + LOGGER.debug("HPACK decoding failed for {}: {}", route, e.getMessage()); + throw new H2Exception(ERROR_COMPRESSION_ERROR, "HPACK decoding failed: " + e.getMessage()); + } catch (IndexOutOfBoundsException e) { + active = false; + LOGGER.debug("HPACK dynamic table mismatch for {}: {}", route, e.getMessage()); + throw new H2Exception(ERROR_COMPRESSION_ERROR, "HPACK state mismatch: " + e.getMessage()); + } + + int decodedSize = 0; + for (int i = 0; i < headers.size(); i += 2) { + decodedSize += headers.get(i).length() + headers.get(i + 1).length() + 32; + if (decodedSize > maxHeaderListSize) { + throw new H2Exception(ERROR_ENHANCE_YOUR_CALM, + "Decoded header list size exceeds limit " + maxHeaderListSize); + } + } + + return headers; + } + + void debitConnectionRecvWindow(int bytes) { + if (bytes <= 0) { + return; + } + connectionRecvWindowLock.lock(); + try { + connectionRecvWindow -= bytes; + } finally { + connectionRecvWindowLock.unlock(); + } + } + + @Override + public void releaseConnectionReceiveWindow(int bytes) { + if (bytes <= 0) { + return; + } + + int increment = 0; + connectionRecvWindowLock.lock(); + try { + connectionRecvWindow += bytes; + pendingConnectionWindowUpdate += bytes; + if (pendingConnectionWindowUpdate >= receiveWindowUpdateThreshold()) { + increment = pendingConnectionWindowUpdate; + pendingConnectionWindowUpdate = 0; + } + } finally { + connectionRecvWindowLock.unlock(); + } + + if (increment > 0) { + stats.connectionWindowUpdates.increment(); + muxer.queueControlFrame(0, H2Muxer.ControlFrameType.WINDOW_UPDATE, increment, writeTimeoutMs); + } + } + + private int receiveWindowUpdateThreshold() { + return Math.max(1, initialWindowSize / H2Constants.WINDOW_UPDATE_THRESHOLD_DIVISOR); + } + + void handleGoaway(int lastStreamId, int errorCode) { + goawayReceived = true; + active = false; + + if (errorCode != ERROR_NO_ERROR) { + LOGGER.debug("Server sent GOAWAY to {}: {}", route, H2Constants.errorCodeName(errorCode)); + } + + state.set(State.SHUTTING_DOWN); + muxer.onGoaway(lastStreamId, errorCode); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ConnectionStats.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ConnectionStats.java new file mode 100644 index 0000000000..c826d8e894 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ConnectionStats.java @@ -0,0 +1,87 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAdder; + +/** + * Internal diagnostic counters for an H2 connection. + * + *

All counters use {@link LongAdder} for contention-free increments on hot paths. + * Max gauges use {@link AtomicLong} with CAS updates. + * + *

Package-private. Not a public API; the shape may change without notice. + */ +final class H2ConnectionStats { + + // --- Frame counters (reader thread) --- + final LongAdder dataFramesRead = new LongAdder(); + final LongAdder dataBytesRead = new LongAdder(); + + // --- Signal batching (reader thread) --- + final LongAdder signalsSent = new LongAdder(); + final LongAdder signalsDeferred = new LongAdder(); + + // --- Flow control --- + final LongAdder streamWindowUpdates = new LongAdder(); + final LongAdder connectionWindowUpdates = new LongAdder(); + final LongAdder connWindowUpdatesReceived = new LongAdder(); + final LongAdder connWindowBytesReceived = new LongAdder(); + final LongAdder dataBytesQueued = new LongAdder(); + final LongAdder dataBytesReleased = new LongAdder(); + + // --- Send window contention (muxer-writer / VT sender) --- + final LongAdder connWindowAcquires = new LongAdder(); // total acquireConnectionWindowUpTo calls + final LongAdder connWindowWaits = new LongAdder(); // calls that had to queue (slow path) + final LongAdder connWindowWaitNs = new LongAdder(); // total nanos spent parked waiting + final AtomicLong maxConnWindowWaiters = new AtomicLong(); // peak waiter queue depth + + // --- Buffer pool --- + final LongAdder buffersBorrowed = new LongAdder(); + final LongAdder buffersReused = new LongAdder(); + final LongAdder buffersAllocated = new LongAdder(); + final LongAdder buffersDropped = new LongAdder(); + + // --- Queue depth gauges --- + final AtomicLong maxQueuedBytesPerStream = new AtomicLong(); + final AtomicLong maxQueuedBytesPerConnection = new AtomicLong(); + + void updateMaxQueued(AtomicLong gauge, long value) { + long prev; + while (value > (prev = gauge.get())) { + if (gauge.compareAndSet(prev, value)) { + return; + } + } + } + + @Override + public String toString() { + return "H2ConnectionStats{" + + "dataFrames=" + dataFramesRead.sum() + + ", dataBytes=" + dataBytesRead.sum() + + ", signalsSent=" + signalsSent.sum() + + ", signalsDeferred=" + signalsDeferred.sum() + + ", streamWU=" + streamWindowUpdates.sum() + + ", connWU=" + connectionWindowUpdates.sum() + + ", connWURx=" + connWindowUpdatesReceived.sum() + + ", connWUBytesRx=" + connWindowBytesReceived.sum() + + ", connAcq=" + connWindowAcquires.sum() + + ", connWaits=" + connWindowWaits.sum() + + ", connWaitMs=" + (connWindowWaitNs.sum() / 1_000_000) + + ", maxConnWaiters=" + maxConnWindowWaiters.get() + + ", queued=" + dataBytesQueued.sum() + + ", released=" + dataBytesReleased.sum() + + ", borrowed=" + buffersBorrowed.sum() + + ", reused=" + buffersReused.sum() + + ", allocated=" + buffersAllocated.sum() + + ", dropped=" + buffersDropped.sum() + + ", maxQueueStream=" + maxQueuedBytesPerStream.get() + + ", maxQueueConn=" + maxQueuedBytesPerConnection.get() + + '}'; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Constants.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Constants.java new file mode 100644 index 0000000000..00097274d4 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Constants.java @@ -0,0 +1,135 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.nio.charset.StandardCharsets; + +/** + * HTTP/2 protocol constants from RFC 9113. + */ +final class H2Constants { + + private H2Constants() {} + + // Shared empty byte array to avoid repeated allocations + static final byte[] EMPTY_BYTES = new byte[0]; + + // Our limit for received header list size (not from server SETTINGS) + static final int DEFAULT_MAX_HEADER_LIST_SIZE = 8192; + + // Connection preface - client must send this first (RFC 9113 Section 3.4) + static final byte[] CONNECTION_PREFACE = + "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.US_ASCII); + + // Frame header size is always 9 bytes + static final int FRAME_HEADER_SIZE = 9; + + // Frame types (RFC 9113 Section 6) + static final int FRAME_TYPE_DATA = 0x0; + static final int FRAME_TYPE_HEADERS = 0x1; + static final int FRAME_TYPE_PRIORITY = 0x2; + static final int FRAME_TYPE_RST_STREAM = 0x3; + static final int FRAME_TYPE_SETTINGS = 0x4; + static final int FRAME_TYPE_PUSH_PROMISE = 0x5; + static final int FRAME_TYPE_PING = 0x6; + static final int FRAME_TYPE_GOAWAY = 0x7; + static final int FRAME_TYPE_WINDOW_UPDATE = 0x8; + static final int FRAME_TYPE_CONTINUATION = 0x9; + + // Frame flags + static final int FLAG_END_STREAM = 0x1; // DATA, HEADERS + static final int FLAG_END_HEADERS = 0x4; // HEADERS, PUSH_PROMISE, CONTINUATION + static final int FLAG_PADDED = 0x8; // DATA, HEADERS, PUSH_PROMISE + static final int FLAG_PRIORITY = 0x20; // HEADERS + static final int FLAG_ACK = 0x1; // SETTINGS, PING + + // Settings identifiers (RFC 9113 Section 6.5.2) + static final int SETTINGS_HEADER_TABLE_SIZE = 0x1; + static final int SETTINGS_ENABLE_PUSH = 0x2; + static final int SETTINGS_MAX_CONCURRENT_STREAMS = 0x3; + static final int SETTINGS_INITIAL_WINDOW_SIZE = 0x4; + static final int SETTINGS_MAX_FRAME_SIZE = 0x5; + static final int SETTINGS_MAX_HEADER_LIST_SIZE = 0x6; + + // Default settings values + static final int DEFAULT_HEADER_TABLE_SIZE = 4096; + static final int DEFAULT_MAX_CONCURRENT_STREAMS = Integer.MAX_VALUE; + static final int DEFAULT_INITIAL_WINDOW_SIZE = 65535; + static final int DEFAULT_MAX_FRAME_SIZE = 16384; + + // Frame size limits + static final int MIN_MAX_FRAME_SIZE = 16384; // 2^14 + static final int MAX_MAX_FRAME_SIZE = 16777215; // 2^24 - 1 + + // WINDOW_UPDATE threshold: send update when window drops below this fraction of initial size. + // Using 1/3 (33%) reduces control frame overhead while leaving enough buffer to avoid stalls. + static final int WINDOW_UPDATE_THRESHOLD_DIVISOR = 3; + + // Error codes (RFC 9113 Section 7) + static final int ERROR_NO_ERROR = 0x0; + static final int ERROR_PROTOCOL_ERROR = 0x1; + static final int ERROR_INTERNAL_ERROR = 0x2; + static final int ERROR_FLOW_CONTROL_ERROR = 0x3; + static final int ERROR_SETTINGS_TIMEOUT = 0x4; + static final int ERROR_STREAM_CLOSED = 0x5; + static final int ERROR_FRAME_SIZE_ERROR = 0x6; + static final int ERROR_REFUSED_STREAM = 0x7; + static final int ERROR_CANCEL = 0x8; + static final int ERROR_COMPRESSION_ERROR = 0x9; + static final int ERROR_CONNECT_ERROR = 0xa; + static final int ERROR_ENHANCE_YOUR_CALM = 0xb; + static final int ERROR_INADEQUATE_SECURITY = 0xc; + static final int ERROR_HTTP_1_1_REQUIRED = 0xd; + + // Pseudo-header field names + static final String PSEUDO_METHOD = ":method"; + static final String PSEUDO_SCHEME = ":scheme"; + static final String PSEUDO_AUTHORITY = ":authority"; + static final String PSEUDO_PATH = ":path"; + static final String PSEUDO_STATUS = ":status"; + + /** + * Get error code name for debugging. + */ + static String errorCodeName(int code) { + return switch (code) { + case ERROR_NO_ERROR -> "NO_ERROR"; + case ERROR_PROTOCOL_ERROR -> "PROTOCOL_ERROR"; + case ERROR_INTERNAL_ERROR -> "INTERNAL_ERROR"; + case ERROR_FLOW_CONTROL_ERROR -> "FLOW_CONTROL_ERROR"; + case ERROR_SETTINGS_TIMEOUT -> "SETTINGS_TIMEOUT"; + case ERROR_STREAM_CLOSED -> "STREAM_CLOSED"; + case ERROR_FRAME_SIZE_ERROR -> "FRAME_SIZE_ERROR"; + case ERROR_REFUSED_STREAM -> "REFUSED_STREAM"; + case ERROR_CANCEL -> "CANCEL"; + case ERROR_COMPRESSION_ERROR -> "COMPRESSION_ERROR"; + case ERROR_CONNECT_ERROR -> "CONNECT_ERROR"; + case ERROR_ENHANCE_YOUR_CALM -> "ENHANCE_YOUR_CALM"; + case ERROR_INADEQUATE_SECURITY -> "INADEQUATE_SECURITY"; + case ERROR_HTTP_1_1_REQUIRED -> "HTTP_1_1_REQUIRED"; + default -> "UNKNOWN(" + code + ")"; + }; + } + + /** + * Get frame type name for debugging. + */ + static String frameTypeName(int type) { + return switch (type) { + case FRAME_TYPE_DATA -> "DATA"; + case FRAME_TYPE_HEADERS -> "HEADERS"; + case FRAME_TYPE_PRIORITY -> "PRIORITY"; + case FRAME_TYPE_RST_STREAM -> "RST_STREAM"; + case FRAME_TYPE_SETTINGS -> "SETTINGS"; + case FRAME_TYPE_PUSH_PROMISE -> "PUSH_PROMISE"; + case FRAME_TYPE_PING -> "PING"; + case FRAME_TYPE_GOAWAY -> "GOAWAY"; + case FRAME_TYPE_WINDOW_UPDATE -> "WINDOW_UPDATE"; + case FRAME_TYPE_CONTINUATION -> "CONTINUATION"; + default -> "UNKNOWN(" + type + ")"; + }; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataInputStream.java new file mode 100644 index 0000000000..118cd5953c --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataInputStream.java @@ -0,0 +1,258 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.util.function.Consumer; + +/** + * Input stream for reading response body from DATA frames. + * + *

Reads directly from per-stream pooled DATA-frame buffers owned by the exchange. + * Chunks are borrowed {@link ByteBuffer}s that are returned to the pool when retired. + * + *

Also provides a {@link #channel()} for ByteBuffer reads. + */ +final class H2DataInputStream extends InputStream { + private static final int BATCH_SIZE = 128; + + private final H2Exchange exchange; + private final Consumer bufferReturner; + private final H2StreamBody.ChunkSlot[] localBatch = new H2StreamBody.ChunkSlot[BATCH_SIZE]; + private final H2StreamBody.ChunkSlot currentChunk = new H2StreamBody.ChunkSlot(); + + private ByteBuffer current; + private int currentFlowControlBytes; + private boolean eof = false; + private boolean closed = false; + private boolean responseClosed; + private final byte[] singleBuff = new byte[1]; + private final byte[] transferBuffer = new byte[65536]; + + H2DataInputStream(H2Exchange exchange, Consumer bufferReturner) { + this.exchange = exchange; + this.bufferReturner = bufferReturner; + for (int i = 0; i < BATCH_SIZE; i++) { + localBatch[i] = new H2StreamBody.ChunkSlot(); + } + } + + /** + * Get a readable channel backed by this stream's data chunks. + * Reads into ByteBuffer destinations without byte[] intermediaries. + */ + ReadableByteChannel channel() { + return new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + return readChannel(dst); + } + + @Override + public boolean isOpen() { + return !closed && !eof; + } + + @Override + public void close() throws IOException { + H2DataInputStream.this.close(); + } + }; + } + + /** + * Read into a ByteBuffer from pooled chunk buffers without going through byte[]. + */ + int readChannel(ByteBuffer dst) throws IOException { + if (closed || eof) { + return -1; + } + if (!dst.hasRemaining()) { + return 0; + } + + if (current == null || !current.hasRemaining()) { + if (!pullNextChunk()) { + return -1; + } + } + + int toCopy = Math.min(current.remaining(), dst.remaining()); + int oldLimit = current.limit(); + current.limit(current.position() + toCopy); + dst.put(current); + current.limit(oldLimit); + + exchange.onDataConsumed(toCopy); + return toCopy; + } + + @Override + public int read() throws IOException { + if (closed || eof) { + return -1; + } + int n = read(singleBuff, 0, 1); + return n == 1 ? (singleBuff[0] & 0xFF) : -1; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (closed || eof) { + return -1; + } else if (len == 0) { + return 0; + } + + if (current == null || !current.hasRemaining()) { + if (!pullNextChunk()) { + return -1; + } + } + + int toCopy = Math.min(current.remaining(), len); + current.get(b, off, toCopy); + exchange.onDataConsumed(toCopy); + return toCopy; + } + + private boolean pullNextChunk() throws IOException { + if (current != null) { + releaseCurrentChunk(); + } + + if (!exchange.awaitNextChunk(currentChunk)) { + eof = true; + responseBodyComplete(); + return false; + } + current = currentChunk.data; + currentFlowControlBytes = currentChunk.flowControlBytes; + return true; + } + + private void releaseCurrentChunk() { + exchange.releaseDataCredit(currentFlowControlBytes); + bufferReturner.accept(currentChunk.data); + currentChunk.clear(); + current = null; + currentFlowControlBytes = 0; + } + + @Override + public int available() { + if (closed || eof || current == null) { + return 0; + } + return current.remaining(); + } + + @Override + public long skip(long n) throws IOException { + if (closed || eof || n <= 0) { + return 0; + } + + long skipped = 0; + + if (current != null && current.hasRemaining()) { + int toSkip = (int) Math.min(current.remaining(), n); + current.position(current.position() + toSkip); + exchange.onDataConsumed(toSkip); + skipped += toSkip; + n -= toSkip; + } + + while (n > 0 && pullNextChunk()) { + int toSkip = (int) Math.min(current.remaining(), n); + current.position(current.position() + toSkip); + exchange.onDataConsumed(toSkip); + skipped += toSkip; + n -= toSkip; + } + + return skipped; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + closed = true; + + if (current != null) { + releaseCurrentChunk(); + } + responseBodyComplete(); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + if (closed || eof) { + return 0; + } + + long transferred = 0; + + if (current != null && current.hasRemaining()) { + transferred += writeCurrentTo(out); + releaseCurrentChunk(); + } + + while (true) { + int drained = exchange.awaitChunks(localBatch, BATCH_SIZE); + if (drained < 0) { + eof = true; + responseBodyComplete(); + return transferred; + } + + for (int i = 0; i < drained; i++) { + H2StreamBody.ChunkSlot chunk = localBatch[i]; + currentChunk.set(chunk.data, chunk.flowControlBytes); + chunk.clear(); + current = currentChunk.data; + currentFlowControlBytes = currentChunk.flowControlBytes; + transferred += writeCurrentTo(out); + releaseCurrentChunk(); + } + } + } + + private int writeCurrentTo(OutputStream out) throws IOException { + int remaining = current.remaining(); + if (current.hasArray()) { + out.write(current.array(), current.arrayOffset() + current.position(), remaining); + current.position(current.limit()); + exchange.onDataConsumed(remaining); + return remaining; + } + + int written = 0; + while (current.hasRemaining()) { + int toCopy = Math.min(current.remaining(), transferBuffer.length); + current.get(transferBuffer, 0, toCopy); + out.write(transferBuffer, 0, toCopy); + written += toCopy; + exchange.onDataConsumed(toCopy); + } + return written; + } + + private void responseBodyComplete() throws IOException { + if (!responseClosed) { + responseClosed = true; + exchange.onResponseStreamClosed(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataOutputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataOutputStream.java new file mode 100644 index 0000000000..f95a6877fa --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2DataOutputStream.java @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +/** + * Output stream for writing request body as DATA frames. + * + *

Uses pooled ByteBuffers from the muxer's ByteAllocator to reduce GC pressure. + */ +final class H2DataOutputStream extends OutputStream { + private final H2Exchange exchange; + private final H2Muxer muxer; + private final Runnable onClose; + private ByteBuffer buffer; + private boolean closed = false; + + H2DataOutputStream(H2Exchange exchange, H2Muxer muxer, int bufferSize) { + this(exchange, muxer, bufferSize, null); + } + + H2DataOutputStream(H2Exchange exchange, H2Muxer muxer, int bufferSize, Runnable onClose) { + this.exchange = exchange; + this.muxer = muxer; + this.onClose = onClose; + this.buffer = bufferSize > 0 ? muxer.borrowBuffer(bufferSize) : null; + } + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } else if (buffer == null) { + throw new IOException("Cannot write body: END_STREAM already sent with headers"); + } + + buffer.put((byte) b); + if (!buffer.hasRemaining()) { + flush(); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (closed) { + throw new IOException("Stream closed"); + } else if (len == 0) { + return; + } else if (buffer == null) { + throw new IOException("Cannot write body: END_STREAM already sent with headers"); + } + + // Fast path: large write, so flush buffer, then write directly + if (len >= buffer.capacity()) { + flush(); + exchange.writeData(b, off, len, false); + return; + } + + while (len > 0) { + int space = buffer.remaining(); + int toCopy = Math.min(space, len); + buffer.put(b, off, toCopy); + off += toCopy; + len -= toCopy; + if (!buffer.hasRemaining()) { + flush(); + } + } + } + + @Override + public void flush() throws IOException { + if (buffer != null && buffer.position() > 0) { + buffer.flip(); + exchange.writeData(buffer, false); + buffer.clear(); + } + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + closed = true; + + try { + if (buffer != null && buffer.position() > 0) { + buffer.flip(); + exchange.writeData(buffer, true); + } else { + exchange.sendEndStream(); + } + } finally { + if (buffer != null) { + buffer.clear(); + muxer.returnBuffer(buffer); + buffer = null; + } + } + if (onClose != null) { + onClose.run(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2EmptyResponseInputStream.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2EmptyResponseInputStream.java new file mode 100644 index 0000000000..2d773e6b3c --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2EmptyResponseInputStream.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +final class H2EmptyResponseInputStream extends InputStream { + private final H2Exchange exchange; + private boolean closed; + + H2EmptyResponseInputStream(H2Exchange exchange) { + this.exchange = exchange; + } + + @Override + public int read() throws IOException { + close(); + return -1; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + if (len == 0) { + return 0; + } + close(); + return -1; + } + + @Override + public long transferTo(OutputStream out) throws IOException { + close(); + return 0; + } + + @Override + public void close() throws IOException { + if (!closed) { + closed = true; + exchange.onResponseStreamClosed(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exception.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exception.java new file mode 100644 index 0000000000..4413a51d6d --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exception.java @@ -0,0 +1,74 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.errorCodeName; + +import java.io.IOException; + +/** + * Exception representing an HTTP/2 protocol error. + * + *

This exception carries an HTTP/2 error code that can be used to send + * RST_STREAM or GOAWAY frames to the peer. + */ +final class H2Exception extends IOException { + + private final int errorCode; + private final int streamId; + + /** + * Create a connection-level HTTP/2 exception. + * + * @param errorCode HTTP/2 error code + * @param message error message + */ + public H2Exception(int errorCode, String message) { + super(message + " (" + errorCodeName(errorCode) + ")"); + this.errorCode = errorCode; + this.streamId = 0; + } + + /** + * Create a stream-level HTTP/2 exception. + * + * @param errorCode HTTP/2 error code + * @param streamId affected stream ID + * @param message error message + */ + public H2Exception(int errorCode, int streamId, String message) { + super("Stream " + streamId + ": " + message + " (" + errorCodeName(errorCode) + ")"); + this.errorCode = errorCode; + this.streamId = streamId; + } + + /** + * Get the HTTP/2 error code. + * + * @return error code + */ + public int errorCode() { + return errorCode; + } + + /** + * Get the affected stream ID. + * + * @return stream ID, or 0 for connection-level errors + */ + public int streamId() { + return streamId; + } + + /** + * Whether this is a connection-level error. + * + * @return true if connection-level, false if stream-level + */ + public boolean isConnectionError() { + return streamId == 0; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exchange.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exchange.java new file mode 100644 index 0000000000..09d759f81e --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Exchange.java @@ -0,0 +1,1249 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_CANCEL; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_FLOW_CONTROL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_PROTOCOL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_STREAM_CLOSED; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_END_STREAM; +import static software.amazon.smithy.java.http.client.h2.H2StreamState.RS_DONE; +import static software.amazon.smithy.java.http.client.h2.H2StreamState.RS_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2StreamState.SS_CLOSED; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.ArrayDeque; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * HTTP/2 exchange implementation for a single stream with multiplexing support. + * + *

This class manages the lifecycle of a single HTTP/2 stream (request/response pair). + * Response data is received from the connection's reader thread into a queue of data chunks. + * Headers and errors are signaled via condition variables. + * + *

Stream Lifecycle

+ *
    + *
  1. Exchange created via {@link H2Muxer#newExchange}, HEADERS sent via {@link H2Muxer#submitHeaders}
  2. + *
  3. {@link #writeRequestBody(DataStream)} writes DATA frames
  4. + *
  5. {@link #responseHeaders()}/{@link #responseStatusCode()} read response HEADERS
  6. + *
  7. {@link #responseBody()} returns input stream for response DATA frames
  8. + *
  9. {@link #close()} sends RST_STREAM if needed and unregisters stream
  10. + *
+ * + *

Data Flow

+ *

The reader thread enqueues DATA frame payloads via {@link #enqueueData}. The user + * thread reads borrowed chunks through {@link H2DataInputStream}. Pooled buffers are + * returned after consumption. Flow control sends WINDOW_UPDATE after DATA frame bytes + * are consumed or discarded. + */ +final class H2Exchange implements HttpExchange { + + // Max frames to acquire flow control for in a single batch (64 frames = 1MB at default 16KB frame size) + private static final int FLOW_CONTROL_BATCH_FRAMES = 64; + + // VarHandle for atomic inWorkQueue CAS + private static final VarHandle IN_WORK_QUEUE_HANDLE; + + static { + try { + IN_WORK_QUEUE_HANDLE = MethodHandles.lookup() + .findVarHandle(H2Exchange.class, "inWorkQueue", boolean.class); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + private final H2Muxer muxer; + private final HttpRequest request; + private volatile int streamId; + + // Stream state machine (encapsulates packed bit-field with CAS operations) + private final H2StreamState state = new H2StreamState(); + + // Pending headers from reader thread (protected by dataLock) + private record PendingHeadersEvent(List fields, boolean endStream) {} + private final ArrayDeque pendingHeadersQueue = new ArrayDeque<>(); + + // === Data chunk queue === + // Stream-owned queue of borrowed DATA frame payload buffers. + // Flow control ensures total queued data never exceeds initial window size. + private final H2StreamBody streamBody; + + // Read-side synchronization (state is in packedState) + private final ReentrantLock dataLock = new ReentrantLock(); + private final Condition dataAvailable = dataLock.newCondition(); + private volatile boolean readWaiterRegistered; + private volatile IOException readError; + + // Stream-level timeouts (tick-based: 1 tick = TIMEOUT_POLL_INTERVAL_MS) + private final long readTimeoutMs; + private final long writeTimeoutMs; + private final int readTimeoutTicks; // Number of ticks before timeout (0 = no timeout) + private final AtomicLong readSeq = new AtomicLong(); // Activity counter, incremented on read activity + private volatile int readDeadlineTick; // 0 = no deadline, >0 = deadline tick + private final AtomicBoolean readTimedOut = new AtomicBoolean(); // At-most-once timeout flag + + // Response headers (status code is in packedState) + private volatile HttpHeaders responseHeaders; + + // Trailer headers per RFC 9113 Section 8.1 + private volatile HttpHeaders trailerHeaders; + + // Content-Length validation per RFC 9113 Section 8.1.1 + private long expectedContentLength = -1; // -1 means not specified + private long receivedContentLength = 0; + + // Request state (endStreamSent is in packedState) + private volatile HttpHeaders requestTrailers; + private final H2StreamRequestBody requestBodyState; + + // Response body input stream + private volatile InputStream responseIn; + private volatile H2DataInputStream responseDataStream; + + // Close guard + private final AtomicBoolean closed = new AtomicBoolean(false); + + // Auto-close tracking: exchange closes when both request and response streams are closed + private static final int BOTH_STREAMS_CLOSED = 2; // request stream + response stream + private final AtomicInteger closedStreamCount = new AtomicInteger(0); + + // === Flow control === + // sendWindow: backed by FlowControlWindow (ReentrantLock + Condition, not a monitor, to avoid + // pinning the carrier when a VT blocks on an exhausted window) + // streamRecvWindow: tracks receive window, accessed under dataLock + private final FlowControlWindow sendWindow; + private final int initialWindowSize; + private int streamRecvWindow; + private int pendingStreamWindowUpdate; + + // === OUTBOUND PATH (VT → Writer) === + // Pending writes queued by the request-writing VT and drained by the muxer writer thread. + // SPSC intrusive list: PendingWrite is the node, avoiding ConcurrentLinkedQueue node churn. + private final PendingWrite pendingWriteStub = new PendingWrite(); + private PendingWrite pendingWriteHead = pendingWriteStub; + private PendingWrite pendingWriteTail = pendingWriteStub; + // Flag to prevent duplicate additions to connection's work queue + volatile boolean inWorkQueue; + + // === WRITE COMPLETION SIGNALING === + // Lock-free signaling using LockSupport to avoid monitor inflation overhead + private volatile Thread waitingWriter; + private volatile boolean writeCompleted; + private volatile Throwable writeError; + + /** + * Create a new HTTP/2 exchange without a stream ID. + * + *

The stream ID will be assigned later via {@link #setStreamId} when + * the muxer allocates it. This allows exchange construction to happen + * outside the critical section. + * + * @param muxer the muxer managing this stream + * @param request the HTTP request + * @param readTimeoutMs timeout in milliseconds for waiting on response data + * @param writeTimeoutMs timeout in milliseconds for waiting on flow control window + * @param initialWindowSize initial flow control window size for this stream + */ + H2Exchange( + H2Muxer muxer, + HttpRequest request, + long readTimeoutMs, + long writeTimeoutMs, + int initialWindowSize + ) { + this.muxer = muxer; + this.request = request; + this.streamId = -1; // Will be set later + this.readTimeoutMs = readTimeoutMs; + this.writeTimeoutMs = writeTimeoutMs; + // Convert timeout to ticks: ceil(readTimeoutMs / pollIntervalMs) + this.readTimeoutTicks = readTimeoutMs <= 0 + ? 0 + : Math.max(1, (int) Math.ceil((double) readTimeoutMs / H2Muxer.TIMEOUT_POLL_INTERVAL_MS)); + this.sendWindow = new FlowControlWindow(muxer.getRemoteInitialWindowSize()); + this.initialWindowSize = initialWindowSize; + this.streamRecvWindow = initialWindowSize; + this.streamBody = new H2StreamBody(128, this::discardChunk); + this.requestBodyState = + new H2StreamRequestBody(this, muxer, this::onRequestStreamClosedUnchecked, state::isEndStreamSent); + } + + /** + * Set the stream ID. Called by muxer when allocating stream ID. + */ + void setStreamId(int streamId) { + this.streamId = streamId; + } + + /** + * Get the stream ID. + */ + int getStreamId() { + return streamId; + } + + /** + * Get read timeout in milliseconds. + */ + long getReadTimeoutMs() { + return readTimeoutMs; + } + + /** + * Get read deadline tick (0 = no deadline). + */ + int getReadDeadlineTick() { + return readDeadlineTick; + } + + /** + * Get read activity sequence number. + */ + long getReadSeq() { + return readSeq.get(); + } + + /** + * Attempt to mark this exchange as timed out. Returns true if successful (first caller wins). + * Used by timeout sweep to ensure at-most-once timeout per exchange. + */ + boolean markReadTimedOut() { + return readTimedOut.compareAndSet(false, true); + } + + /** + * Record read activity: bump sequence and reset deadline. + * Called when headers or data arrive. + * + *

Uses tick-based timeout: instead of calling System.nanoTime() (expensive), + * we read the current tick from the muxer (cheap volatile read) and compute + * the deadline as currentTick + timeoutTicks. + */ + private void onReadActivity() { + if (readTimeoutTicks > 0) { + readSeq.incrementAndGet(); + readDeadlineTick = muxer.currentTimeoutTick() + readTimeoutTicks; + } + } + + /** + * Clear read deadline (no timeout). + */ + private void clearReadDeadline() { + readDeadlineTick = 0; + } + + /** + * Called when headers are encoded and about to be sent. + * Atomically transitions stream state and optionally marks end stream sent. + */ + void onHeadersEncoded(boolean endStream) { + state.onHeadersEncoded(endStream); + } + + // ==================== WRITE COMPLETION SIGNALING ==================== + + /** + * Block until signaled by the writer thread, then check for errors. + * + *

Called by the VT that owns this exchange after submitting work to the muxer. + * Uses lock-free LockSupport signaling to avoid monitor inflation overhead. + * + * @throws IOException if a write error occurred + */ + void awaitWriteCompletion() throws IOException { + // Fast path: already completed + if (writeCompleted) { + writeCompleted = false; + checkWriteError(); + return; + } + + // Register as waiting and park until signaled + waitingWriter = Thread.currentThread(); + try { + while (!writeCompleted) { + LockSupport.park(); + if (Thread.interrupted()) { + throw new IOException("Interrupted waiting for write completion"); + } + } + } finally { + waitingWriter = null; + } + + writeCompleted = false; + checkWriteError(); + } + + private void checkWriteError() throws IOException { + Throwable error = writeError; + if (error != null) { + writeError = null; + if (error instanceof IOException ioe) { + throw ioe; + } + throw new IOException("Write failed", error); + } + } + + /** + * Signal the waiting writer that the write completed successfully. + * + *

Called by the muxer worker thread after completing a write. + * Lock-free: uses volatile write + LockSupport.unpark(). + */ + void signalWriteSuccess() { + writeCompleted = true; + Thread t = waitingWriter; + if (t != null) { + LockSupport.unpark(t); + } + } + + /** + * Signal the waiting writer that the write failed. + * + *

Called by the muxer worker thread when a write error occurs. + * Lock-free: uses volatile writes + LockSupport.unpark(). + * + * @param error the error that occurred + */ + void signalWriteFailure(Throwable error) { + writeError = error; + writeCompleted = true; + Thread t = waitingWriter; + if (t != null) { + LockSupport.unpark(t); + } + } + + /** + * Return a buffer to the muxer's pool. + * + *

Called by the writer thread after consuming a PendingWrite. + * + * @param buffer the buffer to return + */ + void returnBuffer(ByteBuffer buffer) { + muxer.returnBuffer(buffer); + } + + /** + * Called by connection's reader thread to deliver response headers. + * + *

Headers are decoded by the reader thread to ensure HPACK state consistency. + * This method signals the user thread that headers are available. + * + * @param fields the decoded header fields + * @param endStream whether END_STREAM flag was set + */ + void deliverHeaders(List fields, boolean endStream) { + dataLock.lock(); + try { + pendingHeadersQueue.add(new PendingHeadersEvent(fields, endStream)); + signalReadWaiterLocked(); + } finally { + dataLock.unlock(); + } + if (endStream) { + // END_STREAM on a HEADERS frame ends the body, in two cases: an empty response (END_STREAM on + // the response headers, no DATA) or trailers (a HEADERS frame after DATA). DATA frames signal + // end-of-body via enqueueData -> streamBody.complete(); HEADERS frames must do the same, or a + // body reader blocked in H2StreamBody.take() (the trailers case) never sees EOF and stalls + // until the read-timeout watchdog fires, and the completion-based empty-response check in + // responseBody() never trips. The queued event is classified and processed on the consumer + // thread (initial headers in readResponseHeaders, trailers in drainPendingTrailers), keeping + // all header classification single-threaded and in frame order. + streamBody.complete(); + } + } + + /** + * Called by connection when it's closing. + * + *

Signals the user thread that the connection has closed with an error. + */ + void signalConnectionClosed(Throwable error) { + dataLock.lock(); + try { + state.setErrorState(); + this.readError = (error instanceof IOException ioe) ? ioe : new IOException("Connection closed", error); + signalReadWaiterLocked(); + } finally { + dataLock.unlock(); + } + streamBody.fail(readError); + } + + /** + * Called by reader thread when a per-stream error occurs (e.g., RST_STREAM). + * + *

This allows read operations to fail fast with a meaningful error + * instead of timing out. + */ + void signalStreamError(H2Exception error) { + dataLock.lock(); + try { + state.setErrorState(); + this.readError = new IOException("Stream error", error); + signalReadWaiterLocked(); + } finally { + dataLock.unlock(); + } + streamBody.fail(readError); + if (streamId != 0) { + muxer.releaseStream(streamId); + } + } + + /** + * Enqueue a data chunk from the reader thread. + * + *

This method is called by the reader thread to add a byte[] containing + * DATA frame payload to the queue. + * + * @param data the byte buffer containing data, or null for end-stream-only signal + * @param endStream whether END_STREAM flag was set + * @param moreDataBuffered true if more data is already buffered in the socket read buffer, + * used to defer signaling when processing a burst of frames + * @param flowControlBytes DATA frame payload bytes charged to HTTP/2 receive windows + */ + void enqueueData(ByteBuffer data, boolean endStream, boolean moreDataBuffered, int flowControlBytes) { + int length = data != null ? data.remaining() : 0; + + dataLock.lock(); + try { + if (data != null && length > 0) { + streamRecvWindow -= flowControlBytes; + H2ConnectionStats s = muxer.getStats(); + if (s != null) { + s.dataBytesQueued.add(length); + } + } else if (data != null) { + muxer.returnBuffer(data); + data = null; + } + + if (endStream) { + state.setEndStreamReceivedFlag(); + clearReadDeadline(); + } + } finally { + dataLock.unlock(); + } + + if (data != null && length > 0) { + // Defer the consumer wake when more frames are already buffered in the codec: + // the reader will call enqueueData again in a tight loop. The wake happens at + // burst end (moreDataBuffered=false), on stream switch (signalDataAvailable), + // or on END_STREAM (streamBody.complete below). This avoids notify/wait churn + // for intermediate frames in streaming GET responses. + boolean signal = !moreDataBuffered || endStream; + int discardedFlowControlBytes = streamBody.offer(data, flowControlBytes, muxer::returnBuffer, signal); + if (discardedFlowControlBytes > 0) { + releaseDataCredit(discardedFlowControlBytes); + } + } + if (endStream) { + streamBody.complete(); + } + } + + /** + * Signal the consumer that data is available. This flushes a pending burst that was + * enqueued with {@code signal=false} via {@link #enqueueData}. Called by + * {@link H2Connection} when the reader switches away from this stream or exits. + */ + void signalDataAvailable() { + streamBody.signal(); + } + + private void signalReadWaiterLocked() { + if (readWaiterRegistered) { + dataAvailable.signal(); + } + } + + boolean awaitNextChunk(H2StreamBody.ChunkSlot chunk) throws IOException { + if (!state.isResponseHeadersReceived()) { + readResponseHeaders(); + } + + if (!streamBody.take(chunk)) { + if (state.getReadState() == RS_ERROR) { + throw readError; + } + drainPendingTrailers(); + if (state.getStreamState() != SS_CLOSED) { + state.setStreamStateClosed(); + if (streamId > 0) { + muxer.releaseStream(streamId); + } + } + validateContentLength(); + return false; + } + + onReadActivity(); + return true; + } + + /** + * Drain any HEADERS events still queued after the body has been fully read. Once response headers + * are received, a further HEADERS frame can only be trailers (RFC 9113 §8.1); the reader thread + * leaves it in {@code pendingHeadersQueue} for the consumer to classify so that header processing + * stays single-threaded. Processing it here sets {@code trailerHeaders} and the END_STREAM state + * (read-state DONE, cleared read deadline) via {@link #handleHeadersEvent}. + */ + private void drainPendingTrailers() throws IOException { + dataLock.lock(); + try { + PendingHeadersEvent event; + while ((event = pendingHeadersQueue.poll()) != null) { + handleHeadersEvent(event.fields(), event.endStream()); + } + } finally { + dataLock.unlock(); + } + } + + int awaitChunks(H2StreamBody.ChunkSlot[] dest, int maxChunks) throws IOException { + if (!state.isResponseHeadersReceived()) { + readResponseHeaders(); + } + + int drained = streamBody.takeBulk(dest, maxChunks); + if (drained < 0) { + if (state.getReadState() == RS_ERROR) { + throw readError; + } + drainPendingTrailers(); + if (state.getStreamState() != SS_CLOSED) { + state.setStreamStateClosed(); + if (streamId > 0) { + muxer.releaseStream(streamId); + } + } + validateContentLength(); + return -1; + } + + onReadActivity(); + return drained; + } + + /** + * Called by H2DataInputStream when data is consumed. + * + *

Updates content length tracking for actual body bytes only. HTTP/2 receive + * window credit is released separately when the containing DATA chunk is retired. + * + * @param bytesConsumed number of bytes consumed + */ + void onDataConsumed(int bytesConsumed) { + receivedContentLength += bytesConsumed; + } + + /** + * Release receive-window credit for DATA frame payload bytes that have been consumed + * by the application or discarded locally. + */ + void releaseDataCredit(int bytes) { + if (bytes <= 0) { + return; + } + + int increment = 0; + dataLock.lock(); + try { + streamRecvWindow += bytes; + pendingStreamWindowUpdate += bytes; + if (pendingStreamWindowUpdate >= receiveWindowUpdateThreshold()) { + increment = pendingStreamWindowUpdate; + pendingStreamWindowUpdate = 0; + } + } finally { + dataLock.unlock(); + } + + muxer.releaseConnectionReceiveWindow(bytes); + if (increment > 0 && streamId > 0) { + H2ConnectionStats s = muxer.getStats(); + if (s != null) { + s.streamWindowUpdates.increment(); + s.dataBytesReleased.add(bytes); + } + muxer.queueControlFrame(streamId, H2Muxer.ControlFrameType.WINDOW_UPDATE, increment, writeTimeoutMs); + } + } + + /** + * Account for DATA frame payload bytes that were read and discarded without + * becoming application-visible body bytes, such as padding-only DATA frames. + */ + void releaseDiscardedData(int flowControlBytes) { + if (flowControlBytes <= 0) { + return; + } + dataLock.lock(); + try { + streamRecvWindow -= flowControlBytes; + } finally { + dataLock.unlock(); + } + releaseDataCredit(flowControlBytes); + } + + private int receiveWindowUpdateThreshold() { + return Math.max(1, initialWindowSize / H2Constants.WINDOW_UPDATE_THRESHOLD_DIVISOR); + } + + /** + * Called by muxer when SETTINGS changes initial window size. + */ + void adjustSendWindow(int delta) { + sendWindow.adjust(delta); + } + + @Override + public HttpRequest request() { + return request; + } + + OutputStream requestBody() { + // Delegates to requestBodyState.outputStream(), which is itself synchronized; an outer monitor + // here is redundant double-locking. + return requestBodyState.outputStream(); + } + + @Override + public void writeRequestBody(DataStream body) throws IOException { + requestBodyState.writeRequestBody(body); + } + + @Override + public InputStream responseBody() throws IOException { + // Not synchronized: the response body is read by the single VT that owns this exchange, and + // readResponseHeaders() blocks on a Condition. Holding a monitor across that wait would pin the + // carrier thread on JDK 21-23 (fixed by JEP 491 in 24). responseIn/responseDataStream are volatile. + // Ensure we have response headers first + if (!state.isResponseHeadersReceived()) { + readResponseHeaders(); + } + + if (responseIn == null) { + // Optimization: for empty responses, return a null stream to avoid H2DataInputStream allocation. + // But only do this if: + // - content-length is explicitly 0, OR + // - the body stream is completed with no chunk queued (truly empty response). + // isCompletedEmpty() (not isEndStreamReceived() && isEmpty()) is required: the reader thread + // sets the END_STREAM flag before offering the trailing DATA chunk, so the latter pair can + // momentarily read true-while-non-empty under concurrency and drop the body. complete() is + // published with the final chunk, so isCompletedEmpty() only reports empty for a genuinely + // empty body. + boolean isEmpty = expectedContentLength == 0 || streamBody.isCompletedEmpty(); + if (isEmpty) { + responseIn = new H2EmptyResponseInputStream(this); + } else { + H2DataInputStream dataStream = new H2DataInputStream(this, muxer::returnBuffer); + responseDataStream = dataStream; + responseIn = dataStream; + } + } + return responseIn; + } + + @Override + public ReadableByteChannel responseBodyChannel() throws IOException { + // Ensure responseBody() is called to initialize the stream + responseBody(); + if (responseDataStream != null) { + ReadableByteChannel channel = responseDataStream.channel(); + return new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + return channel.read(dst); + } + + @Override + public boolean isOpen() { + return channel.isOpen(); + } + + @Override + public void close() throws IOException { + responseIn.close(); + } + }; + } + return Channels.newChannel(responseIn); + } + + private void onRequestStreamClosed() throws IOException { + if (closedStreamCount.incrementAndGet() == BOTH_STREAMS_CLOSED) { + close(); + } + } + + private void onRequestStreamClosedUnchecked() { + try { + onRequestStreamClosed(); + } catch (IOException e) { + throw new IllegalStateException("Failed closing request stream", e); + } + } + + void onResponseStreamClosed() throws IOException { + if (closedStreamCount.incrementAndGet() == BOTH_STREAMS_CLOSED) { + close(); + } + } + + @Override + public HttpHeaders responseHeaders() throws IOException { + if (!state.isResponseHeadersReceived()) { + readResponseHeaders(); + } + return responseHeaders; + } + + @Override + public int responseStatusCode() throws IOException { + if (!state.isResponseHeadersReceived()) { + readResponseHeaders(); + } + return state.getStatusCode(); + } + + @Override + public HttpVersion responseVersion() { + return HttpVersion.HTTP_2; + } + + @Override + public boolean supportsBidirectionalStreaming() { + return true; + } + + @Override + public void setRequestTrailers(HttpHeaders trailers) { + this.requestTrailers = trailers; + } + + @Override + public void close() { + if (!closed.compareAndSet(false, true)) { + return; + } + + // Close request output if not already closed + try { + requestBodyState.closeIfOpen(); + } catch (IOException ignored) {} + + // If response not fully received and stream was started, queue RST_STREAM + if (!state.isEndStreamReceived() && streamId > 0 && state.getStreamState() != SS_CLOSED) { + // Best-effort cleanup: queue a reset and wake any consumers waiting for data. + muxer.queueControlFrame(streamId, H2Muxer.ControlFrameType.RST_STREAM, ERROR_CANCEL, 100); + // Signal end to any waiting consumers + state.setReadStateDone(); + dataLock.lock(); + try { + dataAvailable.signal(); + } finally { + dataLock.unlock(); + } + } + + // Return all queued buffers to connection pool for reuse + int discardedCredit = 0; + discardedCredit += streamBody.close(); + releaseDataCredit(discardedCredit); + + // Mark stream as closed + state.setStreamStateClosed(); + + // Unregister from connection (only if stream was registered) + if (streamId > 0) { + muxer.releaseStream(streamId); + } + } + + /** + * Wait for the next event from the reader thread. + * + *

Used for waiting on headers and errors. Data is read directly from + * the buffer, not via this method. + * + * @throws SocketTimeoutException if read timeout expires + * @throws IOException if interrupted or error occurred + */ + private void awaitEvent() throws IOException { + dataLock.lock(); + try { + // Wait for headers, error, or data (which also signals) + int rs; + while (pendingHeadersQueue.isEmpty() && (rs = state.getReadState()) != RS_ERROR && rs != RS_DONE) { + try { + readWaiterRegistered = true; + dataAvailable.await(); + } catch (InterruptedException e) { + throw new IOException("Interrupted waiting for response"); + } finally { + readWaiterRegistered = false; + } + } + + // Check for error + if (state.getReadState() == RS_ERROR) { + throw readError; + } + } finally { + dataLock.unlock(); + } + } + + /** + * Read and parse response headers. + * + *

Headers are decoded by the connection's reader thread to ensure + * HPACK dynamic table consistency across all streams. + */ + private void readResponseHeaders() throws IOException { + onReadActivity(); // Start timeout when beginning to read response + + while (!state.isResponseHeadersReceived()) { + awaitEvent(); + + dataLock.lock(); + try { + PendingHeadersEvent headerEvent = pendingHeadersQueue.poll(); + if (headerEvent != null) { + // Process headers (can throw) + handleHeadersEvent(headerEvent.fields(), headerEvent.endStream()); + } else if (state.getReadState() == RS_DONE) { + throw new IOException("Stream ended before response headers received"); + } + } finally { + dataLock.unlock(); + } + } + } + + /** + * Handle a headers event during response reading. + * + * @param fields the decoded header fields + * @param isEndStream whether END_STREAM flag was set + */ + private void handleHeadersEvent(List fields, boolean isEndStream) throws IOException { + int ss = state.getStreamState(); + + // Allow processing headers if the stream is CLOSED but closed cleanly (RS_DONE) + // and we haven't processed the initial headers yet. + // This handles the race where Reader processes HEADERS -> DATA+ES before App processes HEADERS. + boolean cleanCloseRace = (ss == SS_CLOSED && state.getReadState() == RS_DONE + && !state.isResponseHeadersReceived()); + + // Validate stream state per RFC 9113 Section 5.1 + if (ss == SS_CLOSED && !cleanCloseRace) { + throw new H2Exception(ERROR_STREAM_CLOSED, streamId, "Received HEADERS on closed stream"); + } + + if (!state.isResponseHeadersReceived()) { + // This is either informational (1xx) or final response headers + if (fields.isEmpty()) { + throw new IOException("Empty HEADERS frame received"); + } + processResponseHeaders(fields, isEndStream); + } else { + // We already have final response headers - this must be trailers + if (!isEndStream) { + // RFC 9113 Section 8.1: Trailers MUST have END_STREAM. + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "Trailer HEADERS frame missing END_STREAM"); + } + if (!fields.isEmpty()) { + processTrailers(fields); + } + } + + if (isEndStream) { + state.markEndStreamReceived(); // Atomically sets flag, read state to DONE, updates stream state + clearReadDeadline(); // No more data expected + validateContentLength(); + } + // Note: setResponseHeadersReceived already transitions WAITING->READING + } + + /** + * Process response headers with full RFC 9113 validation. + * + *

Headers are already decoded by the reader thread to maintain HPACK state. + * + * @param fields the decoded header fields + * @param isEndStream whether this HEADERS frame has END_STREAM flag + */ + private void processResponseHeaders(List fields, boolean isEndStream) throws IOException { + H2ResponseHeaderProcessor.Result result = + H2ResponseHeaderProcessor.processResponseHeaders(fields, streamId, isEndStream); + + if (result.isInformational()) { + // 1xx response - wait for final response + return; + } + + // This is the final response (2xx-5xx) + this.responseHeaders = result.headers(); + this.expectedContentLength = result.contentLength(); + state.setResponseHeadersReceived(result.statusCode()); + } + + /** + * Process trailer headers per RFC 9113 Section 8.1. + * + *

Trailers are HEADERS sent after DATA with END_STREAM. They MUST NOT + * contain pseudo-headers. + * + *

Headers are already decoded by the reader thread to maintain HPACK state. + * + * @param fields the pre-decoded header fields + */ + private void processTrailers(List fields) throws IOException { + this.trailerHeaders = H2ResponseHeaderProcessor.processTrailers(fields, streamId); + } + + /** + * Validate Content-Length matches actual data received. + * RFC 9113 Section 8.1.1. + */ + private void validateContentLength() throws IOException { + H2ResponseHeaderProcessor.validateContentLength(expectedContentLength, receivedContentLength, streamId); + } + + private int discardChunk(ByteBuffer data, int flowControlBytes) { + muxer.returnBuffer(data); + return flowControlBytes; + } + + /** + * Update stream send window from WINDOW_UPDATE frame. + * + *

Called by the connection's reader thread when a stream-level + * WINDOW_UPDATE is received. This releases capacity to the FlowControlWindow + * and wakes any blocked threads via notifyAll(). + * + * @param increment the window size increment + * @throws H2Exception if the increment causes overflow + */ + void updateStreamSendWindow(int increment) throws H2Exception { + // Check for overflow per RFC 9113 before releasing + int currentWindow = sendWindow.available(); + if ((long) currentWindow + increment > Integer.MAX_VALUE) { + throw new H2Exception(ERROR_FLOW_CONTROL_ERROR, + streamId, + "Stream send window overflow"); + } + sendWindow.release(increment); + } + + /** + * Write DATA frames for request body with flow control. + * + *

Uses batched flow control acquisition to prevent connection window starvation under high concurrency. + * Acquires up to {@value #FLOW_CONTROL_BATCH_FRAMES} frames worth of window at a time. + * + *

Flow: + *

    + *
  1. VT acquires stream and connection flow control in batches
  2. + *
  3. VT copies data to pooled buffers and adds to pendingWrites queue
  4. + *
  5. VT signals writer thread once after all frames are queued
  6. + *
  7. Writer thread drains pendingWrites and writes frames
  8. + *
+ * + * @throws SocketTimeoutException if write timeout expires waiting for flow control window + */ + void writeData(byte[] data, int offset, int length, boolean endStream) throws IOException { + // Wrap byte[] in ByteBuffer and delegate + ByteBuffer buf = ByteBuffer.wrap(data, offset, length); + writeData(buf, endStream); + } + + /** + * Write data from a ByteBuffer as DATA frames. Zero-copy path. + */ + void writeData(ByteBuffer data, boolean endStream) throws IOException { + writeData(data, endStream, false); + } + + void writeReplayableBody(ByteBuffer data, boolean endStream) throws IOException { + writeData(data, endStream, true); + } + + private void writeData(ByteBuffer data, boolean endStream, boolean shareBuffers) throws IOException { + boolean hasTrailers = requestTrailers != null; + int maxFrameSize = muxer.getRemoteMaxFrameSize(); + + while (data.hasRemaining()) { + int remaining = data.remaining(); + int batchSize = Math.min(remaining, maxFrameSize * FLOW_CONTROL_BATCH_FRAMES); + int streamAcquired; + try { + streamAcquired = sendWindow.tryAcquireUpTo(batchSize, writeTimeoutMs); + if (streamAcquired == 0) { + throw new SocketTimeoutException(String.format( + "Write timed out after %dms waiting for stream flow control window", + writeTimeoutMs)); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for stream flow control window", e); + } + + int connAcquired; + try { + connAcquired = muxer.acquireConnectionWindowUpTo(streamAcquired, writeTimeoutMs); + if (connAcquired == 0) { + sendWindow.release(streamAcquired); + throw new SocketTimeoutException(String.format( + "Write timed out after %dms waiting for connection flow control window", + writeTimeoutMs)); + } + if (connAcquired < streamAcquired) { + sendWindow.release(streamAcquired - connAcquired); + } + } catch (InterruptedException e) { + sendWindow.release(streamAcquired); + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for connection flow control window", e); + } catch (SocketTimeoutException e) { + sendWindow.release(streamAcquired); + throw e; + } + + int batchRemaining = connAcquired; + while (batchRemaining > 0 && data.hasRemaining()) { + int toSend = Math.min(Math.min(data.remaining(), maxFrameSize), batchRemaining); + boolean isLastChunk = (toSend == data.remaining()); + int flags = (endStream && isLastChunk && !hasTrailers) ? FLAG_END_STREAM : 0; + + if (shareBuffers) { + int oldLimit = data.limit(); + data.limit(data.position() + toSend); + enqueuePendingWrite(new PendingWrite().initDirect(data.slice(), flags)); + data.position(data.limit()); + data.limit(oldLimit); + } else { + ByteBuffer buf = muxer.borrowBuffer(toSend); + int oldLimit = data.limit(); + data.limit(data.position() + toSend); + buf.put(data); + data.limit(oldLimit); + buf.flip(); + enqueuePendingWrite(new PendingWrite().init(buf, flags)); + } + batchRemaining -= toSend; + } + + // If more data remains, kick the writer now so these frames can drain and + // generate WINDOW_UPDATEs before we try to acquire the next batch. + if (data.hasRemaining()) { + signalPendingWrites(); + } + } + + signalPendingWrites(); + + if (endStream) { + if (hasTrailers) { + muxer.queueTrailers(streamId, requestTrailers); + } + state.markEndStreamSent(); + } + } + + private void signalPendingWrites() { + if (IN_WORK_QUEUE_HANDLE.compareAndSet(this, false, true)) { + muxer.signalDataReady(this); + } + } + + void enqueuePendingWrite(PendingWrite write) { + write.next = null; + pendingWriteTail.next = write; + pendingWriteTail = write; + } + + PendingWrite pollPendingWrite() { + PendingWrite oldHead = pendingWriteHead; + PendingWrite next = oldHead.next; + if (next == null) { + return null; + } + oldHead.next = null; + pendingWriteHead = next; + return next; + } + + boolean hasPendingWrites() { + return pendingWriteHead.next != null; + } + + void writeChannelData(ReadableByteChannel channel, long contentLength, boolean endStream) + throws IOException { + boolean hasTrailers = requestTrailers != null; + int maxFrameSize = muxer.getRemoteMaxFrameSize(); + long remaining = contentLength; + + while (remaining > 0) { + int batchSize = (int) Math.min(remaining, (long) maxFrameSize * FLOW_CONTROL_BATCH_FRAMES); + int connAcquired = acquireSendWindowBatch(batchSize); + int batchRemaining = connAcquired; + try { + while (batchRemaining > 0 && remaining > 0) { + int toRead = (int) Math.min(Math.min(remaining, maxFrameSize), batchRemaining); + boolean lastChunk = remaining == toRead; + int flags = (endStream && lastChunk && !hasTrailers) ? FLAG_END_STREAM : 0; + + ByteBuffer buf = muxer.borrowBuffer(toRead); + try { + buf.limit(toRead); + readFully(channel, buf, toRead); + buf.flip(); + enqueuePendingWrite(new PendingWrite().init(buf, flags)); + } catch (Throwable t) { + muxer.returnBuffer(buf); + throw t; + } + + remaining -= toRead; + batchRemaining -= toRead; + } + } catch (Throwable t) { + releaseUnusedSendWindow(batchRemaining); + if (t instanceof IOException ioe) { + throw ioe; + } + throw new IOException("Failed to stream request body", t); + } + + if (remaining > 0) { + signalPendingWrites(); + } + } + + signalPendingWrites(); + + if (endStream) { + if (hasTrailers) { + muxer.queueTrailers(streamId, requestTrailers); + } + state.markEndStreamSent(); + } + } + + private int acquireSendWindowBatch(int batchSize) throws IOException { + int streamAcquired; + try { + streamAcquired = sendWindow.tryAcquireUpTo(batchSize, writeTimeoutMs); + if (streamAcquired == 0) { + throw new SocketTimeoutException(String.format( + "Write timed out after %dms waiting for stream flow control window", + writeTimeoutMs)); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for stream flow control window", e); + } + + try { + int connAcquired = muxer.acquireConnectionWindowUpTo(streamAcquired, writeTimeoutMs); + if (connAcquired == 0) { + sendWindow.release(streamAcquired); + throw new SocketTimeoutException(String.format( + "Write timed out after %dms waiting for connection flow control window", + writeTimeoutMs)); + } + if (connAcquired < streamAcquired) { + sendWindow.release(streamAcquired - connAcquired); + } + return connAcquired; + } catch (InterruptedException e) { + sendWindow.release(streamAcquired); + Thread.currentThread().interrupt(); + throw new IOException("Interrupted waiting for connection flow control window", e); + } catch (SocketTimeoutException e) { + sendWindow.release(streamAcquired); + throw e; + } + } + + private void releaseUnusedSendWindow(int bytes) { + if (bytes <= 0) { + return; + } + sendWindow.release(bytes); + muxer.releaseConnectionWindow(bytes); + } + + private static void readFully(ReadableByteChannel channel, ByteBuffer buffer, int bytes) throws IOException { + while (buffer.position() < bytes) { + int read = channel.read(buffer); + if (read < 0) { + throw new IOException("Request body ended before expected content-length was fully read"); + } + } + } + + /** + * Send END_STREAM without data, or send trailers if set. + * + *

Uses the same pendingWrites queue as writeData() to ensure proper ordering. + * This prevents END_STREAM from being sent before pending DATA frames. + */ + void sendEndStream() { + if (!state.isEndStreamSent()) { + if (requestTrailers != null) { + muxer.queueTrailers(streamId, requestTrailers); + } else { + // Use pendingWrites queue (same as writeData) to ensure ordering + enqueuePendingWrite(new PendingWrite().initDirect(ByteBuffer.allocate(0), FLAG_END_STREAM)); + + // Signal writer thread + if (IN_WORK_QUEUE_HANDLE.compareAndSet(this, false, true)) { + muxer.signalDataReady(this); + } + } + state.markEndStreamSent(); + } + } + + @Override + public HttpHeaders responseTrailerHeaders() { + return trailerHeaders; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2FrameCodec.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2FrameCodec.java new file mode 100644 index 0000000000..5a8431f77a --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2FrameCodec.java @@ -0,0 +1,959 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.CONNECTION_PREFACE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_FRAME_SIZE_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_PROTOCOL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_ACK; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_END_HEADERS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_END_STREAM; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_PADDED; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_PRIORITY; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_HEADER_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_CONTINUATION; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_DATA; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_GOAWAY; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_HEADERS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PING; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PRIORITY; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PUSH_PROMISE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_RST_STREAM; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_SETTINGS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_WINDOW_UPDATE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.frameTypeName; + +import java.io.IOException; +import java.nio.ByteBuffer; +import software.amazon.smithy.java.io.ByteBufferOutputStream; + +/** + * HTTP/2 frame encoding and decoding. + * + *

HTTP/2 frames have a 9-byte header followed by a variable-length payload: + *

+ * +-----------------------------------------------+
+ * |                 Length (24)                   |
+ * +---------------+---------------+---------------+
+ * |   Type (8)    |   Flags (8)   |
+ * +-+-------------+---------------+-------------------------------+
+ * |R|                 Stream Identifier (31)                      |
+ * +=+=============================================================+
+ * |                   Frame Payload (0...)                      ...
+ * +---------------------------------------------------------------+
+ * 
+ */ +final class H2FrameCodec { + + private final ChannelFrameReader reader; + private final ChannelFrameWriter writer; + private final int maxFrameSize; + + // Write header buffer - used by writer thread only. + private final byte[] writeHeaderBuf = new byte[FRAME_HEADER_SIZE]; + + // Scratch buffer for writing control frames - writer thread only. + private static final int WRITE_SCRATCH_SIZE = 64; + private final byte[] writeScratch = new byte[WRITE_SCRATCH_SIZE]; + + // Reusable buffer for accumulating header blocks when CONTINUATION frames are needed. + private final ByteBufferOutputStream headerBlockBuffer = new ByteBufferOutputStream(4096); + + // Current frame state (filled by nextFrame()) - stateful parser pattern + private int currentType; + private int currentFlags; + private int currentStreamId; + private int currentPayloadLength; + + H2FrameCodec(ChannelFrameReader reader, ChannelFrameWriter writer, int maxFrameSize) { + this.reader = reader; + this.writer = writer; + this.maxFrameSize = maxFrameSize; + } + + /** + * Write the HTTP/2 connection preface (RFC 9113 Section 3.4). + * This must be sent by the client before any frames. + */ + void writeConnectionPreface() throws IOException { + writer.write(CONNECTION_PREFACE); + } + + // ==================== Stateful Parser API ==================== + + /** + * Read the next frame header and store state internally. + * + *

After this call, use {@link #frameType()}, {@link #frameStreamId()}, + * {@link #frameFlags()}, {@link #framePayloadLength()}, and {@link #hasFrameFlag(int)} + * to access the current frame's metadata. + * + *

The payload must be read via {@link #readPayloadInto(byte[], int, int)} or + * {@link #skipBytes(int)} before calling {@code nextFrame()} again. + * + *

This method parses from the reader buffer directly, avoiding intermediate + * copies when possible. + * + * @return frame type (0-255), or -1 on EOF + * @throws IOException if reading fails or frame is malformed + */ + int nextFrame() throws IOException { + // Ensure 9 bytes in buffer, then parse directly from ByteBuffer + if (!reader.ensure(FRAME_HEADER_SIZE)) { + if (reader.buffered() == 0) { + return -1; // Clean EOF + } + throw new IOException("Incomplete frame header: read " + reader.buffered() + " bytes"); + } + + // Parse header directly from reader's ByteBuffer. + ByteBuffer buf = reader.buffer(); + + currentPayloadLength = ((buf.get() & 0xFF) << 16) + | ((buf.get() & 0xFF) << 8) + | (buf.get() & 0xFF); + currentType = buf.get() & 0xFF; + currentFlags = buf.get() & 0xFF; + currentStreamId = ((buf.get() & 0x7F) << 24) + | ((buf.get() & 0xFF) << 16) + | ((buf.get() & 0xFF) << 8) + | (buf.get() & 0xFF); + + // Validate frame size + if (currentPayloadLength > maxFrameSize) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "Frame size " + currentPayloadLength + " exceeds " + maxFrameSize); + } + + // Validate stream ID requirements per RFC 9113 + validateStreamId(currentType, currentStreamId); + + // Validate fixed-size frame payloads per RFC 9113 + validateFrameSize(currentType, currentFlags, currentPayloadLength); + + return currentType; + } + + /** + * Get the current frame's type. + * + * @return frame type (e.g., FRAME_TYPE_DATA, FRAME_TYPE_HEADERS) + */ + int frameType() { + return currentType; + } + + /** + * Get the current frame's flags. + * + * @return frame flags byte + */ + int frameFlags() { + return currentFlags; + } + + /** + * Get the current frame's stream ID. + * + * @return stream identifier (0 for connection-level frames) + */ + int frameStreamId() { + return currentStreamId; + } + + /** + * Get the current frame's payload length. + * + * @return payload length in bytes + */ + int framePayloadLength() { + return currentPayloadLength; + } + + /** + * Check if the current frame has a specific flag set. + * + * @param flag the flag to check (e.g., FLAG_END_STREAM) + * @return true if the flag is set + */ + boolean hasFrameFlag(int flag) { + return (currentFlags & flag) != 0; + } + + /** + * Check if there is more data buffered in the input stream. + * + *

This is used for batched signaling: when processing DATA frames in a burst, + * we can defer waking the consumer thread if more frames are already buffered, + * reducing thread wakeup overhead. + * + * @return true if more data is immediately available without blocking + */ + boolean hasBufferedData() { + return reader.hasBufferedData(); + } + + // ==================== Payload Parsing Methods ==================== + + /** + * Parse SETTINGS frame payload. + * + * @param payload the payload buffer + * @param length the actual payload length + * @return array of {id, value} pairs + * @throws H2Exception if payload is invalid + */ + int[] parseSettings(byte[] payload, int length) throws H2Exception { + if (payload == null || length == 0) { + return new int[0]; + } + + // SETTINGS payload MUST be a multiple of 6 bytes (RFC 9113 Section 6.5) + if (length % 6 != 0) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "SETTINGS frame payload length " + length + " is not a multiple of 6"); + } + + int count = length / 6; + int[] settings = new int[count * 2]; + int pos = 0; + for (int i = 0; i < count; i++) { + int id = ((payload[pos] & 0xFF) << 8) | (payload[pos + 1] & 0xFF); + int value = ((payload[pos + 2] & 0xFF) << 24) + | ((payload[pos + 3] & 0xFF) << 16) + | ((payload[pos + 4] & 0xFF) << 8) + | (payload[pos + 5] & 0xFF); + settings[i * 2] = id; + settings[i * 2 + 1] = value; + pos += 6; + } + return settings; + } + + /** + * Parse GOAWAY frame payload. + * + * @param payload the payload buffer + * @param length the actual payload length + * @return {lastStreamId, errorCode} + * @throws H2Exception if payload is invalid + */ + int[] parseGoaway(byte[] payload, int length) throws H2Exception { + if (payload == null || length < 8) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, "GOAWAY frame payload too short: " + length); + } + + int lastStreamId = ((payload[0] & 0x7F) << 24) + | ((payload[1] & 0xFF) << 16) + | ((payload[2] & 0xFF) << 8) + | (payload[3] & 0xFF); + int errorCode = ((payload[4] & 0xFF) << 24) + | ((payload[5] & 0xFF) << 16) + | ((payload[6] & 0xFF) << 8) + | (payload[7] & 0xFF); + return new int[] {lastStreamId, errorCode}; + } + + /** + * Parse WINDOW_UPDATE frame payload. + * + * @param payload the payload buffer + * @param length the actual payload length + * @return window size increment + * @throws H2Exception if payload is invalid or increment is zero + */ + int parseWindowUpdate(byte[] payload, int length) throws H2Exception { + if (payload == null || length != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "WINDOW_UPDATE frame must have 4-byte payload, got " + length); + } + + int increment = ((payload[0] & 0x7F) << 24) + | ((payload[1] & 0xFF) << 16) + | ((payload[2] & 0xFF) << 8) + | (payload[3] & 0xFF); + + if (increment == 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "WINDOW_UPDATE increment must be non-zero"); + } + + return increment; + } + + /** + * Read and parse WINDOW_UPDATE frame payload directly from stream. + * + *

Parses directly from the reader buffer when possible. Reader thread only. + * + * @return window size increment + * @throws IOException if reading fails + * @throws H2Exception if payload is invalid or increment is zero + */ + int readAndParseWindowUpdate() throws IOException, H2Exception { + if (currentPayloadLength != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "WINDOW_UPDATE frame must have 4-byte payload, got " + currentPayloadLength); + } + + // Ensure 4 bytes in buffer, then parse directly. + if (!reader.ensure(4)) { + throw new IOException("Unexpected EOF reading WINDOW_UPDATE payload"); + } + + ByteBuffer buf = reader.buffer(); + + int increment = ((buf.get() & 0x7F) << 24) + | ((buf.get() & 0xFF) << 16) + | ((buf.get() & 0xFF) << 8) + | (buf.get() & 0xFF); + + if (increment == 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, "WINDOW_UPDATE increment must be non-zero"); + } + + return increment; + } + + /** + * Parse RST_STREAM frame payload. + * + * @param payload the payload buffer + * @param length the actual payload length + * @return error code + * @throws H2Exception if payload is invalid + */ + int parseRstStream(byte[] payload, int length) throws H2Exception { + if (payload == null || length != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "RST_STREAM frame must have 4-byte payload, got " + length); + } + + return ((payload[0] & 0xFF) << 24) + | ((payload[1] & 0xFF) << 16) + | ((payload[2] & 0xFF) << 8) + | (payload[3] & 0xFF); + } + + /** + * Read and parse RST_STREAM frame payload directly from stream. + * + *

Parses directly from the reader buffer when possible. Reader thread only. + * + * @return error code + * @throws IOException if reading fails + * @throws H2Exception if payload is invalid + */ + int readAndParseRstStream() throws IOException, H2Exception { + if (currentPayloadLength != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "RST_STREAM frame must have 4-byte payload, got " + currentPayloadLength); + } + + // Zero-copy: ensure 4 bytes in buffer, then parse directly + if (!reader.ensure(4)) { + throw new IOException("Unexpected EOF reading RST_STREAM payload"); + } + + ByteBuffer buf = reader.buffer(); + + int errorCode = ((buf.get() & 0xFF) << 24) + | ((buf.get() & 0xFF) << 16) + | ((buf.get() & 0xFF) << 8) + | (buf.get() & 0xFF); + + return errorCode; + } + + /** + * Read a complete header block, handling CONTINUATION frames. + * + *

Per RFC 9113 Section 4.3, a header block must be transmitted as a contiguous + * sequence of frames with no interleaved frames of any other type or from any other stream. + * + *

This method uses the stateful parser API. The initial frame's header must have + * already been read via {@link #nextFrame()} and payload via {@link #readPayloadInto}. + * + * @param initialStreamId the stream ID from the initial HEADERS/PUSH_PROMISE frame + * @param initialPayload the payload from the initial frame + * @param initialLength the actual payload length + * @return the complete header block payload + * @throws IOException if reading fails + */ + byte[] readHeaderBlock(int initialStreamId, byte[] initialPayload, int initialLength, int maxAccumulatedSize) + throws IOException { + int initialFlags = currentFlags; + int fragmentOffset = 0; + int fragmentLength = initialLength; + + // RFC 9113 §6.2 (HEADERS) and §6.6 (PUSH_PROMISE): if PADDED, the first byte is pad-length and that + // many trailing bytes are padding. PRIORITY adds a 5-byte priority block right after pad-length (or at + // the very start when not padded). PUSH_PROMISE has 4 bytes of promised-stream-id at the start of the + // post-pad/-priority region (it never sets PRIORITY). All these bytes must be stripped before HPACK. + if (initialPayload != null && initialLength > 0 + && (currentType == FRAME_TYPE_HEADERS || currentType == FRAME_TYPE_PUSH_PROMISE)) { + if ((initialFlags & FLAG_PADDED) != 0) { + // fragmentLength >= 1 is guaranteed by the initialLength > 0 guard above (fragmentLength + // was initialized to initialLength), so the pad-length byte is always present here. + int padLen = initialPayload[fragmentOffset] & 0xFF; + fragmentOffset++; + fragmentLength--; + if (padLen > fragmentLength) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Pad length " + padLen + " exceeds remaining " + frameTypeName(currentType) + + " payload " + fragmentLength); + } + fragmentLength -= padLen; + } + if (currentType == FRAME_TYPE_HEADERS && (initialFlags & FLAG_PRIORITY) != 0) { + if (fragmentLength < 5) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "HEADERS frame with PRIORITY missing 5-byte priority block"); + } + fragmentOffset += 5; + fragmentLength -= 5; + } + if (currentType == FRAME_TYPE_PUSH_PROMISE) { + if (fragmentLength < 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "PUSH_PROMISE frame payload too short for promised stream ID"); + } + fragmentOffset += 4; + fragmentLength -= 4; + } + } + + if ((initialFlags & FLAG_END_HEADERS) != 0) { + // Single-frame header block. Bound check applies to this frame too. + if (fragmentLength > maxAccumulatedSize) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Header block size " + fragmentLength + " exceeds limit " + maxAccumulatedSize); + } + if (initialPayload == null || fragmentLength == 0) { + return H2Constants.EMPTY_BYTES; + } + if (fragmentOffset == 0 && fragmentLength == initialLength) { + return initialPayload; + } + byte[] fragment = new byte[fragmentLength]; + System.arraycopy(initialPayload, fragmentOffset, fragment, 0, fragmentLength); + return fragment; + } + + // Need to read CONTINUATION frames - use reusable buffer with running size cap so a peer + // can't force unbounded growth before the post-accumulation check fires. + headerBlockBuffer.reset(); + if (initialPayload != null && fragmentLength > 0) { + if (fragmentLength > maxAccumulatedSize) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Header block size " + fragmentLength + " exceeds limit " + maxAccumulatedSize); + } + headerBlockBuffer.write(initialPayload, fragmentOffset, fragmentLength); + } + + while (true) { + int type = nextFrame(); + if (type < 0) { + throw new IOException("EOF while reading CONTINUATION frames"); + } + + // Per RFC 9113 Section 4.3: header block must be contiguous + // Only CONTINUATION frames for the same stream are allowed + if (type != FRAME_TYPE_CONTINUATION) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Header block interrupted by " + frameTypeName(type) + + " frame (RFC 9113 Section 4.3 violation)"); + } + + if (currentStreamId != initialStreamId) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "CONTINUATION frame stream ID mismatch: expected " + + initialStreamId + ", got " + currentStreamId); + } + + int contLength = currentPayloadLength; + if (contLength > 0) { + if ((long) headerBlockBuffer.size() + contLength > maxAccumulatedSize) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "Header block size " + ((long) headerBlockBuffer.size() + contLength) + + " exceeds limit " + maxAccumulatedSize); + } + // Read directly into headerBlockBuffer to avoid intermediate allocation + readPayloadIntoBuffer(contLength); + } + + if (hasFrameFlag(FLAG_END_HEADERS)) { + break; + } + } + + // Return view into headerBlockBuffer - valid until next readHeaderBlock call + // Caller must process before next frame read (which is guaranteed since reader thread is single-threaded) + return headerBlockBuffer.array(); + } + + /** + * Get the size of the header block data after a readHeaderBlock call that used CONTINUATION frames. + * + *

When readHeaderBlock returns headerBlockBuffer.array(), use this method to get the valid data length. + * Only valid when the previous readHeaderBlock result came from headerBlockBuffer (not the input payload). + * + * @return size of valid data in the header block buffer + */ + int headerBlockSize() { + return headerBlockBuffer.size(); + } + + private void validateFrameSize(int type, int flags, int length) throws H2Exception { + switch (type) { + case FRAME_TYPE_PING: + // PING frames MUST have exactly 8 bytes payload + if (length != 8) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "PING frame must have 8-byte payload, got " + length); + } + break; + + case FRAME_TYPE_SETTINGS: + // SETTINGS with ACK flag MUST have empty payload + if ((flags & FLAG_ACK) != 0 && length != 0) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "SETTINGS ACK frame must have empty payload, got " + length); + } + // SETTINGS payload must be multiple of 6 (validated in parseSettings) + break; + + case FRAME_TYPE_WINDOW_UPDATE: + // WINDOW_UPDATE frames MUST have exactly 4 bytes payload + if (length != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "WINDOW_UPDATE frame must have 4-byte payload, got " + length); + } + break; + + case FRAME_TYPE_RST_STREAM: + // RST_STREAM frames MUST have exactly 4 bytes payload + if (length != 4) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "RST_STREAM frame must have 4-byte payload, got " + length); + } + break; + + case FRAME_TYPE_PRIORITY: + // PRIORITY frames MUST have exactly 5 bytes payload + if (length != 5) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "PRIORITY frame must have 5-byte payload, got " + length); + } + break; + + case FRAME_TYPE_GOAWAY: + // GOAWAY frames MUST have at least 8 bytes payload + if (length < 8) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "GOAWAY frame must have at least 8-byte payload, got " + length); + } + break; + + case FRAME_TYPE_PUSH_PROMISE: + // PUSH_PROMISE must have at least 4 bytes for the promised stream ID + // (plus 1 byte for pad length if PADDED flag is set) + int pushMinLen = (flags & FLAG_PADDED) != 0 ? 5 : 4; + if (length < pushMinLen) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "PUSH_PROMISE frame must have at least " + pushMinLen + "-byte payload, got " + length); + } + break; + + case FRAME_TYPE_DATA: + // DATA frame with PADDED flag must have at least 1 byte (pad length) + if ((flags & FLAG_PADDED) != 0 && length < 1) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "DATA frame with PADDED flag must have at least 1-byte payload, got " + length); + } + break; + + case FRAME_TYPE_HEADERS: + // HEADERS with PADDED and/or PRIORITY flags need minimum payload sizes + int headersMinLen = 0; + if ((flags & FLAG_PADDED) != 0) { + headersMinLen += 1; // 1 byte for pad length + } + if ((flags & FLAG_PRIORITY) != 0) { + headersMinLen += 5; // 5 bytes for priority data + } + if (length < headersMinLen) { + throw new H2Exception(ERROR_FRAME_SIZE_ERROR, + "HEADERS frame with current flags must have at least " + headersMinLen + + "-byte payload, got " + length); + } + break; + + default: + // Other frame types have variable-length payloads + break; + } + } + + /** + * Validate stream ID requirements per RFC 9113. + */ + private void validateStreamId(int type, int streamId) throws H2Exception { + switch (type) { + case FRAME_TYPE_DATA: + case FRAME_TYPE_HEADERS: + case FRAME_TYPE_PRIORITY: + case FRAME_TYPE_RST_STREAM: + case FRAME_TYPE_CONTINUATION: + // These frames MUST be associated with a stream + if (streamId == 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + frameTypeName(type) + " frame must have non-zero stream ID"); + } + break; + + case FRAME_TYPE_SETTINGS: + case FRAME_TYPE_PING: + case FRAME_TYPE_GOAWAY: + // These frames MUST NOT be associated with a stream + if (streamId != 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + frameTypeName(type) + " frame must have stream ID 0, got " + streamId); + } + break; + + case FRAME_TYPE_WINDOW_UPDATE: + // Can be on connection (0) or stream (non-zero) + break; + + case FRAME_TYPE_PUSH_PROMISE: + // Must be on a stream + if (streamId == 0) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + "PUSH_PROMISE frame must have non-zero stream ID"); + } + break; + + default: + // Unknown frame types - ignore per RFC 9113 + break; + } + } + + /** + * Write a frame to the output stream. + * + * @param type frame type + * @param flags frame flags + * @param streamId stream identifier + * @param payload frame payload (may be null or empty) + * @throws IOException if writing fails + */ + void writeFrame(int type, int flags, int streamId, byte[] payload) throws IOException { + writeFrame(type, flags, streamId, payload, 0, payload != null ? payload.length : 0); + } + + /** + * Write a frame to the output stream. + * + *

This method is NOT synchronized. Callers must ensure exclusive access + * to the output stream (e.g., via H2Muxer's writer thread). + * + *

The underlying UnsyncBufferedOutputStream will buffer small writes. + * For payloads larger than the buffer size, the header is buffered and the + * payload is written directly to the underlying stream. This is safe because + * the writer thread has exclusive access - no interleaving can occur. + * + * @param type frame type + * @param flags frame flags + * @param streamId stream identifier + * @param payload frame payload buffer + * @param offset offset in payload buffer + * @param length number of bytes to write from payload + * @throws IOException if writing fails + */ + void writeFrame( + int type, + int flags, + int streamId, + byte[] payload, + int offset, + int length + ) throws IOException { + // Validate stream ID is a valid 31-bit unsigned value + if (streamId < 0) { + throw new IllegalArgumentException("Invalid stream ID: " + streamId); + } + + // Note: For outbound frames, the caller (H2Exchange.writeData) is responsible for + // chunking data according to the peer's MAX_FRAME_SIZE setting. We don't validate + // here because maxFrameSize is our receive limit, not the peer's. + + // Write header (using writeHeaderBuf - caller must ensure exclusive access) + writeHeaderBuf[0] = (byte) ((length >> 16) & 0xFF); + writeHeaderBuf[1] = (byte) ((length >> 8) & 0xFF); + writeHeaderBuf[2] = (byte) (length & 0xFF); + writeHeaderBuf[3] = (byte) type; + writeHeaderBuf[4] = (byte) flags; + writeHeaderBuf[5] = (byte) ((streamId >> 24) & 0x7F); // Clear reserved bit + writeHeaderBuf[6] = (byte) ((streamId >> 16) & 0xFF); + writeHeaderBuf[7] = (byte) ((streamId >> 8) & 0xFF); + writeHeaderBuf[8] = (byte) (streamId & 0xFF); + + writer.write(writeHeaderBuf); + + // Write payload + if (length > 0 && payload != null) { + writer.write(payload, offset, length); + } + } + + /** + * Write a frame with a ByteBuffer payload. Zero-copy path for DATA frames. + * The buffer must be in read mode (position at start of data, limit at end). + */ + void writeFrame(int type, int flags, int streamId, ByteBuffer payload) throws IOException { + if (streamId < 0) { + throw new IllegalArgumentException("Invalid stream ID: " + streamId); + } + + int length = payload != null ? payload.remaining() : 0; + + writeHeaderBuf[0] = (byte) ((length >> 16) & 0xFF); + writeHeaderBuf[1] = (byte) ((length >> 8) & 0xFF); + writeHeaderBuf[2] = (byte) (length & 0xFF); + writeHeaderBuf[3] = (byte) type; + writeHeaderBuf[4] = (byte) flags; + writeHeaderBuf[5] = (byte) ((streamId >> 24) & 0x7F); + writeHeaderBuf[6] = (byte) ((streamId >> 16) & 0xFF); + writeHeaderBuf[7] = (byte) ((streamId >> 8) & 0xFF); + writeHeaderBuf[8] = (byte) (streamId & 0xFF); + + writer.write(writeHeaderBuf); + + if (length > 0 && payload != null) { + writer.write(payload); + } + } + + /** + * Write HEADERS frame, splitting into CONTINUATION frames if needed. + */ + void writeHeaders(int streamId, byte[] headerBlock, int offset, int length, boolean endStream) throws IOException { + if (length <= maxFrameSize) { + // Fits in single frame + int flags = FLAG_END_HEADERS; + if (endStream) { + flags |= FLAG_END_STREAM; + } + writeFrame(FRAME_TYPE_HEADERS, flags, streamId, headerBlock, offset, length); + } else { + // Need to split across HEADERS + CONTINUATION frames + int pos = offset; + int end = offset + length; + + // First frame: HEADERS (no END_HEADERS flag) + int firstFlags = endStream ? FLAG_END_STREAM : 0; + writeFrame(FRAME_TYPE_HEADERS, firstFlags, streamId, headerBlock, pos, maxFrameSize); + pos += maxFrameSize; + + // Middle frames: CONTINUATION (no END_HEADERS flag) + while (pos + maxFrameSize < end) { + writeFrame(FRAME_TYPE_CONTINUATION, 0, streamId, headerBlock, pos, maxFrameSize); + pos += maxFrameSize; + } + + // Last frame: CONTINUATION with END_HEADERS + int remaining = end - pos; + writeFrame(FRAME_TYPE_CONTINUATION, FLAG_END_HEADERS, streamId, headerBlock, pos, remaining); + } + } + + /** + * Write SETTINGS frame. + */ + void writeSettings(int... settings) throws IOException { + if (settings.length % 2 != 0) { + throw new IllegalArgumentException("Settings must be id-value pairs"); + } + + // Each pair is 2 ints (id + value) and encodes to 6 bytes (2 + 4) + byte[] payload = new byte[settings.length * 3]; + int pos = 0; + for (int i = 0; i < settings.length; i += 2) { + int id = settings[i]; + int value = settings[i + 1]; + payload[pos++] = (byte) ((id >> 8) & 0xFF); + payload[pos++] = (byte) (id & 0xFF); + payload[pos++] = (byte) ((value >> 24) & 0xFF); + payload[pos++] = (byte) ((value >> 16) & 0xFF); + payload[pos++] = (byte) ((value >> 8) & 0xFF); + payload[pos++] = (byte) (value & 0xFF); + } + + writeFrame(FRAME_TYPE_SETTINGS, 0, 0, payload); + } + + /** + * Write SETTINGS acknowledgment. + */ + void writeSettingsAck() throws IOException { + writeFrame(FRAME_TYPE_SETTINGS, FLAG_ACK, 0, (byte[]) null); + } + + /** + * Write GOAWAY frame. + * + *

Debug data is written directly using writeAscii() to avoid allocation + * when the debug string is ASCII (the common case for error messages). + */ + void writeGoaway(int lastStreamId, int errorCode, String debugData) throws IOException { + int debugLen = debugData != null ? debugData.length() : 0; + int payloadLen = 8 + debugLen; + + // Write frame header manually to avoid allocating payload array + writeHeaderBuf[0] = (byte) ((payloadLen >> 16) & 0xFF); + writeHeaderBuf[1] = (byte) ((payloadLen >> 8) & 0xFF); + writeHeaderBuf[2] = (byte) (payloadLen & 0xFF); + writeHeaderBuf[3] = (byte) FRAME_TYPE_GOAWAY; + writeHeaderBuf[4] = 0; // flags + writeHeaderBuf[5] = 0; // stream ID = 0 + writeHeaderBuf[6] = 0; + writeHeaderBuf[7] = 0; + writeHeaderBuf[8] = 0; + writer.write(writeHeaderBuf); + + // Write fixed 8-byte GOAWAY payload (lastStreamId + errorCode) using scratch buffer + writeScratch[0] = (byte) ((lastStreamId >> 24) & 0x7F); + writeScratch[1] = (byte) ((lastStreamId >> 16) & 0xFF); + writeScratch[2] = (byte) ((lastStreamId >> 8) & 0xFF); + writeScratch[3] = (byte) (lastStreamId & 0xFF); + writeScratch[4] = (byte) ((errorCode >> 24) & 0xFF); + writeScratch[5] = (byte) ((errorCode >> 16) & 0xFF); + writeScratch[6] = (byte) ((errorCode >> 8) & 0xFF); + writeScratch[7] = (byte) (errorCode & 0xFF); + writer.write(writeScratch, 0, 8); + + // Write debug data directly as ASCII (avoids String.getBytes allocation) + if (debugLen > 0) { + writer.writeAscii(debugData); + } + } + + /** + * Write WINDOW_UPDATE frame. + * Uses scratch buffer - caller must have exclusive access (writer thread). + */ + void writeWindowUpdate(int streamId, int windowSizeIncrement) throws IOException { + if (windowSizeIncrement <= 0) { + throw new IllegalArgumentException("Invalid window size increment: " + windowSizeIncrement); + } + + // Use scratch buffer to avoid allocation + writeScratch[0] = (byte) ((windowSizeIncrement >> 24) & 0x7F); + writeScratch[1] = (byte) ((windowSizeIncrement >> 16) & 0xFF); + writeScratch[2] = (byte) ((windowSizeIncrement >> 8) & 0xFF); + writeScratch[3] = (byte) (windowSizeIncrement & 0xFF); + writeFrame(FRAME_TYPE_WINDOW_UPDATE, 0, streamId, writeScratch, 0, 4); + } + + /** + * Write RST_STREAM frame. + * Uses scratch buffer - caller must have exclusive access (writer thread). + */ + void writeRstStream(int streamId, int errorCode) throws IOException { + // Use scratch buffer to avoid allocation + writeScratch[0] = (byte) ((errorCode >> 24) & 0xFF); + writeScratch[1] = (byte) ((errorCode >> 16) & 0xFF); + writeScratch[2] = (byte) ((errorCode >> 8) & 0xFF); + writeScratch[3] = (byte) (errorCode & 0xFF); + writeFrame(FRAME_TYPE_RST_STREAM, 0, streamId, writeScratch, 0, 4); + } + + /** + * Flush the output stream. + * + *

Caller must ensure exclusive access to the output stream. + */ + void flush() throws IOException { + writer.flush(); + } + + /** + * Read payload bytes directly into a provided buffer. + * + *

This method is used by the reader thread to read DATA frame payloads + * directly into an exchange's buffer, avoiding an intermediate allocation. + * + *

Copies directly from buffered data when the entire payload is already buffered. When partially + * buffered, drains the buffer then reads directly from the underlying stream + * to avoid redundant buffer fill/copy overhead. + * + * @param dest the destination buffer + * @param offset offset in the destination buffer + * @param length number of bytes to read + * @throws IOException if reading fails or EOF is reached before all bytes are read + */ + void readPayloadInto(byte[] dest, int offset, int length) throws IOException { + reader.readInto(dest, offset, length); + } + + /** + * Read DATA frame payload directly into a pooled ByteBuffer. + * Data goes from channel to destination, bypassing the internal buffer + * when possible. + * + * @param dest ByteBuffer in write mode + * @param length bytes to read + */ + void readPayloadDirect(ByteBuffer dest, int length) throws IOException { + reader.readIntoDirect(dest, length); + } + + /** + * Read payload bytes directly into the headerBlockBuffer. + * + *

Used when reading CONTINUATION frames to avoid allocating intermediate byte[] arrays. + * + * @param length number of bytes to read + * @throws IOException if reading fails or EOF is reached before all bytes are read + */ + private void readPayloadIntoBuffer(int length) throws IOException { + // Read into headerBlockBuffer via scratch + while (length > 0) { + int toRead = Math.min(length, writeScratch.length); + reader.readInto(writeScratch, 0, toRead); + headerBlockBuffer.write(writeScratch, 0, toRead); + length -= toRead; + } + } + + /** + * Read a single byte from the input stream. + * + *

Used for reading pad length in padded DATA frames without allocating. + * Uses direct reader-buffer access when possible. + * + * @return the byte value (0-255) + * @throws IOException if reading fails or EOF is reached + */ + int readByte() throws IOException { + return reader.readByte(); + } + + /** + * Skip the specified number of bytes in the input stream. + * + *

Used to skip past padding bytes in DATA frames. Uses direct buffer + * consume for small skips (common case), falling back to stream skip + * for larger amounts. + * + * @param length number of bytes to skip + * @throws IOException if skipping fails or EOF is reached before all bytes are skipped + */ + void skipBytes(int length) throws IOException { + reader.skip(length); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Muxer.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Muxer.java new file mode 100644 index 0000000000..d15a4a15dd --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2Muxer.java @@ -0,0 +1,910 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_INITIAL_WINDOW_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_MAX_CONCURRENT_STREAMS; +import static software.amazon.smithy.java.http.client.h2.H2Constants.DEFAULT_MAX_FRAME_SIZE; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_ACK; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_DATA; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FRAME_TYPE_PING; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; +import java.util.function.BiConsumer; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.io.ByteBufferOutputStream; + +/** + * HTTP/2 stream multiplexer that coordinates concurrent streams over a single connection. + * + *

This class manages: + *

    + *
  • Stream registry and lifecycle
  • + *
  • Connection and stream flow control
  • + *
  • HPACK encoding and frame writing (via dedicated writer thread)
  • + *
  • Work queue processing with batching
  • + *
+ * + *

Threading Model

+ *
    + *
  • Reader thread calls {@code on*} methods to deliver inbound frames
  • + *
  • User VTs call {@code newExchange}, queue writes via exchanges
  • + *
  • Writer thread processes queued work: encodes headers, writes frames
  • + *
+ */ +final class H2Muxer implements AutoCloseable { + + /** + * Callback interface for connection-level operations. + */ + interface ConnectionCallback { + boolean isAcceptingStreams(); + + int getRemoteMaxHeaderListSize(); + + default void releaseConnectionReceiveWindow(int bytes) {} + } + + enum ControlFrameType { + RST_STREAM, + WINDOW_UPDATE, + SETTINGS_ACK, + PING, + GOAWAY + } + + // The resolution of the tick-based timeout system, used to check for read timeouts. + static final int TIMEOUT_POLL_INTERVAL_MS = 100; + private static final int DEFAULT_POOLED_BUFFER_COUNT = 128; + private static final int DEFAULT_POOLED_BUFFER_SIZE = 4 * 1024; + private static final int MAX_POOLED_BUFFER_SIZE = 64 * 1024; + + // Reusable singleton work items + private static final H2MuxerWorkItem.CheckDataQueue CHECK_DATA_QUEUE = H2MuxerWorkItem.CheckDataQueue.INSTANCE; + private static final H2MuxerWorkItem.Shutdown SHUTDOWN = H2MuxerWorkItem.Shutdown.INSTANCE; + private static final H2MuxerWorkItem.WriteSettingsAck SETTINGS_ACK = H2MuxerWorkItem.WriteSettingsAck.INSTANCE; + + // Static method reference to avoid allocation in hot timeout check path + private static final BiConsumer TIMEOUT_CHECKER = H2Muxer::checkExchangeTimeout; + + // === STREAM REGISTRY === + private final StreamRegistry streams = new StreamRegistry(); + private final AtomicInteger activeStreamCount = new AtomicInteger(0); + private final AtomicInteger nextStreamId = new AtomicInteger(1); + private volatile int lastAllocatedStreamId = 0; + + // === SETTINGS FROM PEER === + private volatile int remoteMaxConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS; + private volatile int remoteInitialWindowSize = DEFAULT_INITIAL_WINDOW_SIZE; + private volatile int remoteMaxFrameSize = DEFAULT_MAX_FRAME_SIZE; + + // === CONNECTION FLOW CONTROL === + private final FlowControlWindow connectionSendWindow; + private final ConcurrentLinkedQueue sendWindowWaiters = new ConcurrentLinkedQueue<>(); + + /** + * Waiter for connection send window. Used for fair FIFO queuing. + */ + private static final class SendWindowWaiter { + final Thread thread; + final int maxBytes; + final long deadlineNs; + volatile int acquired; + volatile boolean done; + volatile boolean cancelled; + + SendWindowWaiter(Thread thread, int maxBytes, long deadlineNs) { + this.thread = thread; + this.maxBytes = maxBytes; + this.deadlineNs = deadlineNs; + } + } + + // === STATE === + private volatile boolean accepting = true; + private volatile boolean running = true; + private volatile boolean goawayReceived = false; + private volatile int goawayLastStreamId = Integer.MAX_VALUE; + private volatile IOException writeError; + + // Tick-based timeout: incremented every TIMEOUT_POLL_INTERVAL_MS by watchdog + private volatile int timeoutTick; + + // === DEPENDENCIES === + private final ConnectionCallback connectionCallback; + private final H2FrameCodec frameCodec; + private final ByteAllocator allocator; + private final int initialWindowSize; + private volatile Runnable streamReleaseCallback; + + // === WORK QUEUES === + // Queues plus LockSupport keep cross-thread work submission lightweight without DelayScheduler overhead. + private final ConcurrentLinkedQueue workQueue = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue dataWorkQueue = new ConcurrentLinkedQueue<>(); + private final AtomicBoolean dataWorkPending = new AtomicBoolean(false); + + // === HEADER ENCODER (only accessed by writer thread) === + private final H2RequestHeaderEncoder headerEncoder; + private final AtomicInteger pendingTableSizeUpdate = new AtomicInteger(-1); + + // === WRITER THREAD === + private final Thread workerThread; + + /** + * Create a new multiplexer. + * + * @param connectionCallback callback for connection-level state + * @param frameCodec the frame codec for writing + * @param initialTableSize initial HPACK table size + * @param threadName name for the writer thread + * @param initialWindowSize initial flow control window size + */ + H2Muxer( + ConnectionCallback connectionCallback, + H2FrameCodec frameCodec, + int initialTableSize, + String threadName, + int initialWindowSize + ) { + this.connectionCallback = connectionCallback; + this.frameCodec = frameCodec; + this.initialWindowSize = initialWindowSize; + this.connectionSendWindow = new FlowControlWindow(DEFAULT_INITIAL_WINDOW_SIZE); + this.allocator = new ByteAllocator( + DEFAULT_POOLED_BUFFER_COUNT, + initialWindowSize, + Math.min(initialWindowSize, MAX_POOLED_BUFFER_SIZE), + Math.min(DEFAULT_POOLED_BUFFER_SIZE, Math.min(initialWindowSize, MAX_POOLED_BUFFER_SIZE))); + this.headerEncoder = new H2RequestHeaderEncoder( + new HpackEncoder(initialTableSize), + new ByteBufferOutputStream(512)); + this.workerThread = Thread.ofVirtual().name(threadName).start(this::workerLoop); + } + + // ==================== LIFECYCLE ==================== + + /** + * Create a new exchange for a request. + */ + H2Exchange newExchange(HttpRequest request, long readTimeoutMs, long writeTimeoutMs) throws IOException { + if (!accepting) { + throw new IOException("Connection is not accepting new streams"); + } + + if (goawayReceived) { + int nextId = nextStreamId.get(); + if (nextId > goawayLastStreamId) { + throw new IOException("Connection received GOAWAY with lastStreamId=" + + goawayLastStreamId + ", cannot create stream " + nextId); + } + } + + if (!tryReserveStream()) { + throw new IOException("Connection at max concurrent streams: " + activeStreamCount.get() + + " (limit: " + remoteMaxConcurrentStreams + ")"); + } + + return new H2Exchange(this, request, readTimeoutMs, writeTimeoutMs, initialWindowSize); + } + + /** + * Close all exchanges gracefully. + */ + void closeExchanges(Duration timeout) { + accepting = false; + streams.forEach(null, (exchange, _ignore) -> { + exchange.signalConnectionClosed(null); + }); + + long deadline = System.nanoTime() + timeout.toNanos(); + while (activeStreamCount.get() > 0 && System.nanoTime() < deadline) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + // Force close any remaining exchanges and clear slots + streams.clearAndClose(exchange -> { + try { + exchange.close(); + } catch (Exception ignored) { + // trying to close, ignore failure + } + }); + activeStreamCount.set(0); + } + + H2Exchange getExchange(int streamId) { + return streams.get(streamId); + } + + int getActiveStreamCount() { + return activeStreamCount.get(); + } + + boolean canAcceptMoreStreams() { + return accepting && !goawayReceived && activeStreamCount.get() < remoteMaxConcurrentStreams; + } + + /** + * Get the active stream count if this muxer can accept more streams, or -1 if not. + * Combines the availability check with getting the count to avoid redundant atomic reads. + */ + int getActiveStreamCountIfAccepting() { + if (!accepting || goawayReceived) { + return -1; + } + int count = activeStreamCount.get(); + return count < remoteMaxConcurrentStreams ? count : -1; + } + + int getLastAllocatedStreamId() { + return lastAllocatedStreamId; + } + + private boolean tryReserveStream() { + while (true) { + int current = activeStreamCount.get(); + if (current >= remoteMaxConcurrentStreams) { + return false; + } + if (activeStreamCount.compareAndSet(current, current + 1)) { + return true; + } + } + } + + void releaseStream(int streamId) { + if (streams.remove(streamId)) { + activeStreamCount.decrementAndGet(); + Runnable cb = streamReleaseCallback; + if (cb != null) { + cb.run(); + } + } + } + + void releaseStreamSlot() { + activeStreamCount.decrementAndGet(); + Runnable cb = streamReleaseCallback; + if (cb != null) { + cb.run(); + } + } + + int allocateAndRegisterStream(H2Exchange exchange) { + int streamId = nextStreamId.getAndAdd(2); + exchange.setStreamId(streamId); + streams.put(streamId, exchange); + lastAllocatedStreamId = streamId; + return streamId; + } + + void onConnectionClosing(Throwable error) { + accepting = false; + streams.forEach(error, H2Exchange::signalConnectionClosed); + } + + void onSettingsReceived(int maxConcurrentStreams, int initialWindowSize, int maxFrameSize) { + this.remoteMaxConcurrentStreams = maxConcurrentStreams; + this.remoteMaxFrameSize = maxFrameSize; + + int delta = initialWindowSize - this.remoteInitialWindowSize; + this.remoteInitialWindowSize = initialWindowSize; + if (delta != 0) { + streams.forEach(delta, H2Exchange::adjustSendWindow); + } + } + + void onGoaway(int lastStreamId, int errorCode) { + goawayReceived = true; + goawayLastStreamId = lastStreamId; + accepting = false; + + H2Exception refusedError = new H2Exception( + errorCode, + "Stream affected by GOAWAY (lastStreamId=" + lastStreamId + + ", error=" + H2Constants.errorCodeName(errorCode) + ")"); + streams.forEachMatching( + streamId -> streamId > lastStreamId, + exchange -> exchange.signalConnectionClosed(refusedError)); + } + + // ==================== FLOW CONTROL ==================== + + /** + * Acquire up to the requested bytes from the connection flow control window. + * Uses FIFO queuing to prevent thundering herd and starvation. + * + * @param maxBytes maximum bytes to acquire + * @param timeoutMs timeout if window is empty + * @return bytes acquired (0 if timeout) + */ + int acquireConnectionWindowUpTo(int maxBytes, long timeoutMs) throws SocketTimeoutException, InterruptedException { + if (stats != null) { + stats.connWindowAcquires.increment(); + } + // Fast path: no waiters and window available + if (sendWindowWaiters.isEmpty()) { + int acquired = connectionSendWindow.tryAcquireNonBlocking(maxBytes); + if (acquired > 0) { + return acquired; + } + } + + // Slow path: queue and wait for fair access + long waitStart = System.nanoTime(); + long deadlineNs = waitStart + timeoutMs * 1_000_000L; + var waiter = new SendWindowWaiter(Thread.currentThread(), maxBytes, deadlineNs); + sendWindowWaiters.add(waiter); + if (stats != null) { + stats.connWindowWaits.increment(); + stats.updateMaxQueued(stats.maxConnWindowWaiters, sendWindowWaiters.size()); + } + + try { + while (!waiter.done) { + if (System.nanoTime() >= deadlineNs) { + return 0; // Timeout + } + LockSupport.park(); // Untimed - woken by wakeWaiters() or watchdog + if (Thread.interrupted()) { + throw new InterruptedException(); + } + } + if (stats != null) { + stats.connWindowWaitNs.add(System.nanoTime() - waitStart); + } + return waiter.acquired; + } finally { + waiter.cancelled = true; // wakeWaiters() will skip and remove + } + } + + void releaseConnectionWindow(int bytes) { + int currentWindow = connectionSendWindow.available(); + if ((long) currentWindow + bytes <= Integer.MAX_VALUE) { + connectionSendWindow.release(bytes); + } + + wakeWaiters(); + } + + void releaseConnectionReceiveWindow(int bytes) { + connectionCallback.releaseConnectionReceiveWindow(bytes); + } + + /** + * Wake queued waiters in FIFO order until window is exhausted. + */ + private void wakeWaiters() { + SendWindowWaiter waiter; + while ((waiter = sendWindowWaiters.peek()) != null) { + // Skip cancelled waiters + if (waiter.cancelled) { + sendWindowWaiters.poll(); + continue; + } + int acquired = connectionSendWindow.tryAcquireNonBlocking(waiter.maxBytes); + if (acquired > 0) { + waiter.acquired = acquired; + waiter.done = true; + sendWindowWaiters.poll(); + LockSupport.unpark(waiter.thread); + } else { + // No more window available + break; + } + } + } + + /** + * Wake waiters that have timed out so they can check their deadline. + */ + private void wakeTimedOutWaiters() { + long now = System.nanoTime(); + for (SendWindowWaiter waiter : sendWindowWaiters) { + if (!waiter.done && !waiter.cancelled && now >= waiter.deadlineNs) { + LockSupport.unpark(waiter.thread); + } + } + } + + // ==================== WRITE QUEUE ==================== + + void signalDataReady(H2Exchange exchange) { + if (!accepting) { + return; + } + dataWorkQueue.offer(exchange); + // CAS ensures only one thread enqueues CHECK_DATA_QUEUE per batch + if (dataWorkPending.compareAndSet(false, true)) { + enqueue(CHECK_DATA_QUEUE); + } + } + + /** + * Enqueue a work item with deadline and signal the writer. + */ + private void enqueue(H2MuxerWorkItem item, long timeoutMs) { + item.deadlineTick = deadlineTick(timeoutMs); + workQueue.add(item); + signalWriter(); + } + + /** + * Enqueue a work item without timeout and signal the writer. + */ + private void enqueue(H2MuxerWorkItem item) { + item.deadlineTick = 0; + workQueue.add(item); + signalWriter(); + } + + void queueControlFrame(int streamId, ControlFrameType frameType, Object payload, long timeoutMs) { + H2MuxerWorkItem item = switch (frameType) { + case RST_STREAM -> new H2MuxerWorkItem.WriteRst(streamId, (Integer) payload); + case WINDOW_UPDATE -> new H2MuxerWorkItem.WriteWindowUpdate(streamId, (Integer) payload); + case SETTINGS_ACK -> SETTINGS_ACK; + case PING -> new H2MuxerWorkItem.WritePing((byte[]) payload, true); // PING needs ACK + case GOAWAY -> { + Object[] args = (Object[]) payload; + yield new H2MuxerWorkItem.WriteGoaway((Integer) args[0], (Integer) args[1], (String) args[2]); + } + }; + enqueue(item, timeoutMs); + } + + void queueTrailers(int streamId, HttpHeaders trailers) { + enqueue(new H2MuxerWorkItem.WriteTrailers(streamId, trailers)); + } + + /** + * Submit a HEADERS frame for encoding and writing. + * Always succeeds; queued work is bounded by stream slots. + * Timeout is enforced by watchdog sweep checking deadlineTick. + * + *

After calling this method, the caller should call {@link H2Exchange#awaitWriteCompletion()} + * to block until the write completes, then read the stream ID from the exchange. + * + * @param request the HTTP request + * @param exchange the exchange + * @param endStream whether END_STREAM should be set + * @param timeoutMs timeout for write completion (checked by watchdog) + * @return true if submitted, false if not accepting + */ + boolean submitHeaders(HttpRequest request, H2Exchange exchange, boolean endStream, long timeoutMs) { + if (!accepting) { + return false; + } + enqueue(new H2MuxerWorkItem.EncodeHeaders(request, exchange, endStream), timeoutMs); + return true; + } + + // ==================== BUFFER ALLOCATION ==================== + + ByteBuffer borrowBuffer(int minSize) { + return allocator.borrow(minSize); + } + + void returnBuffer(ByteBuffer buffer) { + allocator.release(buffer); + } + + /** + * Borrow a raw byte[] for control frame payloads (HEADERS, SETTINGS, etc.). + * These are small, short-lived, and parsed with byte[]-based APIs. + */ + byte[] borrowByteArray(int size) { + return new byte[size]; + } + + // ==================== SETTINGS ==================== + + int getRemoteMaxFrameSize() { + return remoteMaxFrameSize; + } + + int getRemoteInitialWindowSize() { + return remoteInitialWindowSize; + } + + int getInitialWindowSize() { + return initialWindowSize; + } + + private H2ConnectionStats stats; + + void setStats(H2ConnectionStats stats) { + this.stats = stats; + allocator.setStats(stats); + } + + H2ConnectionStats getStats() { + return stats; + } + + void setStreamReleaseCallback(Runnable callback) { + this.streamReleaseCallback = callback; + } + + /** + * Get the current timeout tick for deadline calculations. + * Called by exchanges when read activity occurs. + */ + int currentTimeoutTick() { + return timeoutTick; + } + + /** + * Convert timeout in milliseconds to deadline tick. + * Returns 0 if timeoutMs <= 0 (no timeout). + */ + private int deadlineTick(long timeoutMs) { + if (timeoutMs <= 0) { + return 0; + } + int timeoutTicks = (int) Math.ceil((double) timeoutMs / TIMEOUT_POLL_INTERVAL_MS); + return timeoutTick + timeoutTicks; + } + + /** + * Signal the writer thread that work is available. + * Uses LockSupport.unpark which is safe to call even if thread isn't parked. + */ + private void signalWriter() { + LockSupport.unpark(workerThread); + } + + void setMaxTableSize(int newSize) { + pendingTableSizeUpdate.set(newSize); + } + + IOException getWriteError() { + return writeError; + } + + /** + * Check all active streams for read timeouts, called periodically from the worker loop. + * + *

Read timeouts are approximate: ±100ms due to the polling interval. This is acceptable because network + * I/O already has inherent latency variance, and callers setting a "30s timeout" don't expect millisecond + * precision. + * + *

Uses a tick-based system where the watchdog increments a global tick counter every poll interval. + * Exchanges track their deadline as a tick number rather than nanoseconds, eliminating System.nanoTime() + * calls from the hot path. + * + *

There is an unavoidable race: data could arrive just after we decide to timeout but before we signal. + * We mitigate this by checking both deadline and activity sequence twice - we only timeout if the stream + * appears expired and idle across two snapshots. The remaining race window is small and acceptable because + * timeouts are approximate and failure is recoverable at the caller layer. + */ + private void checkReadTimeouts(int tick) { + streams.forEach(tick, TIMEOUT_CHECKER); + } + + private static void checkExchangeTimeout(H2Exchange exchange, int nowTick) { + long seq1 = exchange.getReadSeq(); + int d1 = exchange.getReadDeadlineTick(); + if (d1 <= 0 || nowTick < d1) { + return; + } + + // Second snapshot: did anything change while we were looking? + long seq2 = exchange.getReadSeq(); + int d2 = exchange.getReadDeadlineTick(); + if (seq1 != seq2 || d2 <= 0 || nowTick < d2) { + return; + } + + // Try to claim the timeout - only first caller wins + if (!exchange.markReadTimedOut()) { + return; + } + + exchange.signalConnectionClosed(new SocketTimeoutException( + "Read timeout: no data received for " + exchange.getReadTimeoutMs() + "ms")); + } + + /** + * Check for write timeouts by examining the head of the work queue. + * If the head item has a deadline that has passed, fail the connection. + * Since items are processed in order, if head is stuck, everything is stuck. + */ + private void checkWriteTimeouts(int tick) { + H2MuxerWorkItem head = workQueue.peek(); + if (head != null && head.deadlineTick > 0 && tick >= head.deadlineTick) { + failWriter(new SocketTimeoutException( + "Write timeout: work item stuck in queue (deadline tick " + head.deadlineTick + + ", current tick " + tick + ")")); + } + } + + // ==================== WRITER THREAD ==================== + + private void workerLoop() { + var batch = new ArrayList(64); + IOException failure = null; + long lastTimeoutCheck = System.currentTimeMillis(); + + try { + while (running) { + boolean wroteFrames = false; + // Drain all available work items from the queue + H2MuxerWorkItem item; + while ((item = workQueue.poll()) != null) { + if (item instanceof H2MuxerWorkItem.Shutdown) { + completeBatch(batch, new IOException("Muxer shutting down")); + return; + } + if (!(item instanceof H2MuxerWorkItem.CheckDataQueue)) { + batch.add(item); + } + } + + if (!batch.isEmpty()) { + wroteFrames = processBatch(batch); + } + + boolean processedData = false; + H2Exchange exchange; + while ((exchange = dataWorkQueue.poll()) != null) { + processExchangePendingWrites(exchange); + processedData = true; + } + + // Reset flag only after draining to avoid race where VT signals while we're still processing, + // causing extra wake-ups and flushes + dataWorkPending.set(false); + + if (wroteFrames || processedData) { + try { + frameCodec.flush(); + completeBatch(batch, null); + } catch (IOException e) { + completeBatch(batch, e); + failWriter(e); + return; + } + } + + // Re-check to close the race: a VT may have offered to dataWorkQueue AFTER we drained + // but BEFORE we reset dataWorkPending - in that case its CAS failed and it didn't unpark us. + if (!dataWorkQueue.isEmpty() || !workQueue.isEmpty()) { + continue; + } + + // Check for timeouts periodically using tick-based system + long now = System.currentTimeMillis(); + if (now - lastTimeoutCheck >= TIMEOUT_POLL_INTERVAL_MS) { + // Single-writer (muxer thread) / multi-reader pattern. Only this thread increments. + @SuppressWarnings("NonAtomicOperationOnVolatileField") + int tick = ++timeoutTick; + checkReadTimeouts(tick); + checkWriteTimeouts(tick); + wakeTimedOutWaiters(); + lastTimeoutCheck = now; + } + + // Park until signaled or timeout interval elapses (for watchdog) + // LockSupport.parkNanos is VT-friendly and doesn't create DelayScheduler tasks + LockSupport.parkNanos(TIMEOUT_POLL_INTERVAL_MS * 1_000_000L); + } + } catch (Throwable t) { + failure = new IOException("Writer thread crashed", t); + } finally { + if (failure != null) { + failWriter(failure); + } else { + drainAndFailPending(new IOException("Muxer shutting down")); + } + } + } + + private void processExchangePendingWrites(H2Exchange exchange) { + int streamId = exchange.getStreamId(); + PendingWrite pw; + while ((pw = exchange.pollPendingWrite()) != null) { + ByteBuffer buffer = pw.borrowed ? pw.data : null; + try { + frameCodec.writeFrame(FRAME_TYPE_DATA, pw.flags, streamId, pw.data); + } catch (IOException e) { + if (buffer != null) { + exchange.returnBuffer(buffer); + } + failWriter(e); + return; + } + if (buffer != null) { + exchange.returnBuffer(buffer); + } + pw.reset(); + } + + // Reset inWorkQueue only after draining to avoid race where VT adds writes + // and re-enqueues while still processing. + exchange.inWorkQueue = false; + + // Check if more writes arrived while we were draining. If so, re-enqueue. + // Note: there's a benign race where VT could also enqueue via CAS, causing + // a duplicate entry - but processExchangePendingWrites handles empty queues fine. + if (exchange.hasPendingWrites()) { + exchange.inWorkQueue = true; + dataWorkQueue.offer(exchange); + } + } + + private boolean processBatch(ArrayList batch) throws IOException { + if (batch.isEmpty()) { + return false; + } + + for (H2MuxerWorkItem item : batch) { + processItem(item); + } + return true; + } + + private void completeBatch(ArrayList batch, IOException error) { + if (batch.isEmpty()) { + return; + } + try { + for (H2MuxerWorkItem item : batch) { + completeItem(item, error); + } + } finally { + batch.clear(); + } + } + + private void processItem(H2MuxerWorkItem item) throws IOException { + switch (item) { + case H2MuxerWorkItem.EncodeHeaders h -> processEncodeHeaders(h); + case H2MuxerWorkItem.WriteTrailers t -> processWriteTrailers(t); + case H2MuxerWorkItem.WriteRst r -> frameCodec.writeRstStream(r.streamId, r.errorCode); + case H2MuxerWorkItem.WriteGoaway g -> frameCodec.writeGoaway(g.lastStreamId, g.errorCode, g.debugData); + case H2MuxerWorkItem.WriteWindowUpdate w -> frameCodec.writeWindowUpdate(w.streamId, w.increment); + case H2MuxerWorkItem.WriteSettingsAck s -> frameCodec.writeSettingsAck(); + case H2MuxerWorkItem.WritePing p -> + frameCodec.writeFrame(FRAME_TYPE_PING, p.ack ? FLAG_ACK : 0, 0, p.payload); + case H2MuxerWorkItem.Shutdown s -> { + } + case H2MuxerWorkItem.CheckDataQueue c -> { + } + } + } + + private void processEncodeHeaders(H2MuxerWorkItem.EncodeHeaders req) throws IOException { + H2Exchange exchange = req.exchange; + + if (!connectionCallback.isAcceptingStreams()) { + throw new IOException("Connection is not accepting new streams"); + } + + int streamId = allocateAndRegisterStream(exchange); + + try { + // Atomically read and clear to avoid losing updates from concurrent setMaxTableSize calls + int tableUpdate = pendingTableSizeUpdate.getAndSet(-1); + if (tableUpdate >= 0) { + headerEncoder.setMaxTableSize(tableUpdate); + } + + headerEncoder.encodeHeaders(req.request, connectionCallback.getRemoteMaxHeaderListSize()); + + exchange.onHeadersEncoded(req.endStream); + frameCodec.writeHeaders(streamId, headerEncoder.buffer(), 0, headerEncoder.size(), req.endStream); + + // For end-stream requests (e.g. GET), signal the VT immediately after headers are buffered. + // The VT can start waiting for the response while the flush happens asynchronously. + // For requests with a body, the VT needs to wait for the flush before sending data frames. + if (req.endStream) { + exchange.signalWriteSuccess(); + req.signaled = true; + } + + } catch (Exception e) { + releaseStream(streamId); + if (e instanceof IOException ioe) { + throw ioe; + } + throw new IOException("Encoding failed", e); + } + } + + private void processWriteTrailers(H2MuxerWorkItem.WriteTrailers req) throws IOException { + headerEncoder.encodeTrailers(req.trailers); + frameCodec.writeHeaders(req.streamId, headerEncoder.buffer(), 0, headerEncoder.size(), true); + } + + private void completeItem(H2MuxerWorkItem item, IOException error) { + // Get the exchange to signal (only EncodeHeaders has an exchange directly) + if (item instanceof H2MuxerWorkItem.EncodeHeaders h) { + // Skip if already signaled early (end-stream fast path) + if (h.signaled && error == null) { + return; + } + H2Exchange exchange = h.exchange; + if (error == null) { + exchange.signalWriteSuccess(); + } else { + exchange.signalWriteFailure(error); + } + } + } + + private void failWriter(IOException e) { + if (writeError == null) { + writeError = e; + } + accepting = false; + drainAndFailPending(writeError); + } + + private void drainAndFailPending(IOException error) { + H2MuxerWorkItem item; + while ((item = workQueue.poll()) != null) { + completeItem(item, error); + } + } + + @Override + public void close() { + accepting = false; + + // Signal writer to process remaining work before we shut down + signalWriter(); + + long deadline = System.currentTimeMillis() + 1000; + while (!workQueue.isEmpty() && System.currentTimeMillis() < deadline) { + signalWriter(); // Keep signaling in case writer parks between checks + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + running = false; + enqueue(SHUTDOWN); + + if (workerThread != null) { + workerThread.interrupt(); + try { + workerThread.join(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + drainAndFailPending(new IOException("Muxer shutting down")); + } + + void shutdownNow() { + accepting = false; + running = false; + enqueue(SHUTDOWN); + if (workerThread != null) { + workerThread.interrupt(); + } + drainAndFailPending(new IOException("Muxer shutting down")); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2MuxerWorkItem.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2MuxerWorkItem.java new file mode 100644 index 0000000000..e1c5f05f1d --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2MuxerWorkItem.java @@ -0,0 +1,98 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; + +/** + * Work items processed by the writer thread. + * Base class includes deadlineTick for watchdog-based timeout, eliminating + * the need for a separate TimedWorkItem wrapper allocation. + */ +abstract sealed class H2MuxerWorkItem { + /** + * Deadline tick for timeout (0 = no timeout). Set before enqueueing. + */ + int deadlineTick; + + static final class EncodeHeaders extends H2MuxerWorkItem { + final HttpRequest request; + final H2Exchange exchange; + final boolean endStream; + boolean signaled; + + EncodeHeaders(HttpRequest request, H2Exchange exchange, boolean endStream) { + this.request = request; + this.exchange = exchange; + this.endStream = endStream; + } + } + + static final class WriteTrailers extends H2MuxerWorkItem { + final int streamId; + final HttpHeaders trailers; + + WriteTrailers(int streamId, HttpHeaders trailers) { + this.streamId = streamId; + this.trailers = trailers; + } + } + + static final class WriteRst extends H2MuxerWorkItem { + final int streamId; + final int errorCode; + + WriteRst(int streamId, int errorCode) { + this.streamId = streamId; + this.errorCode = errorCode; + } + } + + static final class WriteGoaway extends H2MuxerWorkItem { + final int lastStreamId; + final int errorCode; + final String debugData; + + WriteGoaway(int lastStreamId, int errorCode, String debugData) { + this.lastStreamId = lastStreamId; + this.errorCode = errorCode; + this.debugData = debugData; + } + } + + static final class WriteWindowUpdate extends H2MuxerWorkItem { + final int streamId; + final int increment; + + WriteWindowUpdate(int streamId, int increment) { + this.streamId = streamId; + this.increment = increment; + } + } + + static final class WriteSettingsAck extends H2MuxerWorkItem { + static final WriteSettingsAck INSTANCE = new WriteSettingsAck(); + } + + static final class WritePing extends H2MuxerWorkItem { + final byte[] payload; + final boolean ack; + + WritePing(byte[] payload, boolean ack) { + this.payload = payload; + this.ack = ack; + } + } + + static final class Shutdown extends H2MuxerWorkItem { + static final Shutdown INSTANCE = new Shutdown(); + } + + static final class CheckDataQueue extends H2MuxerWorkItem { + static final CheckDataQueue INSTANCE = new CheckDataQueue(); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2RequestHeaderEncoder.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2RequestHeaderEncoder.java new file mode 100644 index 0000000000..f65f052387 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2RequestHeaderEncoder.java @@ -0,0 +1,220 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.PSEUDO_AUTHORITY; +import static software.amazon.smithy.java.http.client.h2.H2Constants.PSEUDO_METHOD; +import static software.amazon.smithy.java.http.client.h2.H2Constants.PSEUDO_PATH; +import static software.amazon.smithy.java.http.client.h2.H2Constants.PSEUDO_SCHEME; + +import java.io.IOException; +import java.util.Set; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.io.ByteBufferOutputStream; + +/** + * Encodes HTTP/2 request headers and trailers using HPACK compression. + * + *

This class handles the encoding of request HEADERS frames per RFC 9113, + * including pseudo-header construction, connection header filtering, and + * sensitive header marking. + * + *

RFC 9113 Compliance

+ *
    + *
  • Section 8.3.1: Request pseudo-headers (:method, :scheme, :authority, :path)
  • + *
  • Section 8.2.2: CONNECT method handling (no :scheme or :path)
  • + *
  • Section 8.2.1: Connection-specific headers must not be sent
  • + *
  • Section 10.5.1: Header list size validation
  • + *
+ * + *

Zero-Copy Design

+ *

The encoder reuses an internal buffer across requests. After encoding, callers access + * the encoded data via {@link #buffer()} and {@link #size()} to avoid copying. The buffer + * is only valid until the next encode call. + * + *

Threading

+ *

This class is NOT thread-safe. It must only be used from the writer thread + * to maintain HPACK encoder state consistency. + */ +final class H2RequestHeaderEncoder { + + /** Headers that must not be sent over HTTP/2 (connection-specific per RFC 9113 Section 8.2.1). */ + private static final Set CONNECTION_HEADERS = Set.of( + "connection", + "keep-alive", + "proxy-connection", + "transfer-encoding", + "upgrade", + "host"); + + /** Headers that should not be indexed in HPACK (contain sensitive data). */ + private static final Set SENSITIVE_HEADERS = Set.of( + "authorization", + "cookie", + "proxy-authorization", + "set-cookie"); + + private final HpackEncoder hpackEncoder; + private final ByteBufferOutputStream encodeBuffer; + + /** + * Create a new request header encoder. + * + * @param hpackEncoder the HPACK encoder to use + * @param encodeBuffer the buffer to encode headers into + */ + H2RequestHeaderEncoder(HpackEncoder hpackEncoder, ByteBufferOutputStream encodeBuffer) { + this.hpackEncoder = hpackEncoder; + this.encodeBuffer = encodeBuffer; + } + + /** + * Set the maximum HPACK dynamic table size. + * + * @param maxSize the new maximum size + */ + void setMaxTableSize(int maxSize) { + hpackEncoder.setMaxTableSize(maxSize); + } + + /** + * Encode request headers into the internal buffer. + * + *

After calling this method, use {@link #buffer()} and {@link #size()} to access the encoded data. + * The data is valid until the next encode call. + * + * @param request the HTTP request + * @param maxHeaderListSize maximum header list size allowed by peer (Integer.MAX_VALUE if unlimited) + * @throws IOException if encoding fails or header list size exceeds limit + */ + void encodeHeaders(HttpRequest request, int maxHeaderListSize) throws IOException { + encodeBuffer.reset(); + hpackEncoder.beginHeaderBlock(encodeBuffer); + + long headerListSize = 0; + String method = request.method(); + boolean isConnect = "CONNECT".equalsIgnoreCase(method); + + String authority = getAuthority(request); + String scheme = isConnect ? null : request.uri().getScheme(); + String path = isConnect ? null : getPath(request); + + // Encode pseudo-headers (must come first per RFC 9113 Section 8.3) + hpackEncoder.encodeHeader(encodeBuffer, PSEUDO_METHOD, method, false); + headerListSize += PSEUDO_METHOD.length() + method.length() + 32; + + if (!isConnect) { + hpackEncoder.encodeHeader(encodeBuffer, PSEUDO_SCHEME, scheme, false); + headerListSize += PSEUDO_SCHEME.length() + (scheme != null ? scheme.length() : 0) + 32; + } + + hpackEncoder.encodeHeader(encodeBuffer, PSEUDO_AUTHORITY, authority, false); + headerListSize += PSEUDO_AUTHORITY.length() + authority.length() + 32; + + if (!isConnect) { + hpackEncoder.encodeHeader(encodeBuffer, PSEUDO_PATH, path, false); + headerListSize += PSEUDO_PATH.length() + path.length() + 32; + } + + // Encode regular headers + for (var entry : request.headers().map().entrySet()) { + String name = entry.getKey(); + if (CONNECTION_HEADERS.contains(name)) { + continue; + } + boolean isTe = "te".equals(name); + boolean sensitive = SENSITIVE_HEADERS.contains(name); + for (String value : entry.getValue()) { + // RFC 9113 Section 8.2.1: TE header may only contain "trailers" + if (isTe && !"trailers".equalsIgnoreCase(value)) { + continue; + } + hpackEncoder.encodeHeader(encodeBuffer, name, value, sensitive); + headerListSize += name.length() + value.length() + 32; + } + } + + // Validate header list size per RFC 9113 Section 10.5.1 + if (maxHeaderListSize != Integer.MAX_VALUE && headerListSize > maxHeaderListSize) { + throw new IOException( + "Header list size (" + headerListSize + ") exceeds limit (" + maxHeaderListSize + ")"); + } + } + + /** + * Encode trailer headers into the internal buffer. + * + *

After calling this method, use {@link #buffer()} and {@link #size()} to access the encoded data. + * + * @param trailers the trailer headers + * @throws IOException if encoding fails or trailers contain pseudo-headers + */ + void encodeTrailers(HttpHeaders trailers) throws IOException { + encodeBuffer.reset(); + hpackEncoder.beginHeaderBlock(encodeBuffer); + + for (var entry : trailers.map().entrySet()) { + String name = entry.getKey(); + // RFC 9113 Section 8.1: Trailers MUST NOT contain pseudo-headers + if (name.startsWith(":")) { + throw new IOException("Trailers must not contain pseudo-header: " + name); + } + boolean sensitive = SENSITIVE_HEADERS.contains(name); + for (String value : entry.getValue()) { + hpackEncoder.encodeHeader(encodeBuffer, name, value, sensitive); + } + } + } + + /** + * Get the internal buffer containing encoded data. + * Valid from index 0 to {@link #size()} - 1. + * + * @return the internal buffer array + */ + byte[] buffer() { + return encodeBuffer.array(); + } + + /** + * Get the size of the encoded data in the buffer. + * + * @return number of valid bytes in {@link #buffer()} + */ + int size() { + return encodeBuffer.size(); + } + + /** + * Build the :authority pseudo-header value. + */ + private static String getAuthority(HttpRequest request) { + String host = request.uri().getHost(); + int port = request.uri().getPort(); + String scheme = request.uri().getScheme(); + if (port == -1 || (port == 443 && "https".equalsIgnoreCase(scheme)) + || (port == 80 && "http".equalsIgnoreCase(scheme))) { + return host; + } + return host + ":" + port; + } + + /** + * Build the :path pseudo-header value. + */ + private static String getPath(HttpRequest request) { + String path = request.uri().getPath(); + if (path == null || path.isEmpty()) { + path = "/"; + } + String query = request.uri().getQuery(); + if (query != null && !query.isEmpty()) { + path = path + "?" + query; + } + return path; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessor.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessor.java new file mode 100644 index 0000000000..c2bfad19df --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessor.java @@ -0,0 +1,138 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static software.amazon.smithy.java.http.client.h2.H2Constants.ERROR_PROTOCOL_ERROR; +import static software.amazon.smithy.java.http.client.h2.H2Constants.PSEUDO_STATUS; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.ModifiableHttpHeaders; + +/** + * Processes HTTP/2 response headers and trailers with RFC 9113 validation. + * + *

Headers are passed as flat List<String>: [name0, value0, name1, value1, ...]. + */ +final class H2ResponseHeaderProcessor { + + private static final Set REQUEST_PSEUDO_HEADERS = Set.of( + ":method", + ":scheme", + ":authority", + ":path"); + + record Result(HttpHeaders headers, int statusCode, long contentLength) { + static final Result INFORMATIONAL = new Result(null, -1, -1); + + boolean isInformational() { + return this == INFORMATIONAL; + } + } + + private H2ResponseHeaderProcessor() {} + + /** + * Process response headers. + * + * @param fields flat list [name0, value0, name1, value1, ...] + */ + static Result processResponseHeaders(List fields, int streamId, boolean isEndStream) + throws IOException { + ModifiableHttpHeaders headers = HttpHeaders.ofModifiable(); + int parsedStatusCode = -1; + boolean seenRegularHeader = false; + long contentLength = -1; + + for (int i = 0; i < fields.size(); i += 2) { + String name = fields.get(i); + String value = fields.get(i + 1); + + if (name.startsWith(":")) { + if (seenRegularHeader) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + streamId, + "Pseudo-header '" + name + "' appears after regular header"); + } + + if (name.equals(PSEUDO_STATUS)) { + if (parsedStatusCode != -1) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "Expected a single :status header"); + } + try { + parsedStatusCode = Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new IOException("Invalid :status value: " + value); + } + } else if (REQUEST_PSEUDO_HEADERS.contains(name)) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + streamId, + "Request pseudo-header '" + name + "' in response"); + } else { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + streamId, + "Unknown pseudo-header '" + name + "' in response"); + } + } else { + seenRegularHeader = true; + if ("content-length".equals(name)) { + try { + long parsedLength = Long.parseLong(value); + if (contentLength != -1 && contentLength != parsedLength) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "Multiple Content-Length values"); + } + contentLength = parsedLength; + } catch (NumberFormatException e) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "Invalid Content-Length: " + value); + } + } + headers.addHeaderCanonical(name, value); + } + } + + if (parsedStatusCode == -1) { + throw new IOException("Response missing :status pseudo-header"); + } + + if (parsedStatusCode >= 100 && parsedStatusCode < 200) { + if (isEndStream) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "1xx response must not have END_STREAM"); + } + return Result.INFORMATIONAL; + } + + return new Result(headers, parsedStatusCode, contentLength); + } + + /** + * Process trailer headers. + * + * @param fields flat list [name0, value0, name1, value1, ...] + */ + static HttpHeaders processTrailers(List fields, int streamId) throws IOException { + ModifiableHttpHeaders trailers = HttpHeaders.ofModifiable(); + for (int i = 0; i < fields.size(); i += 2) { + String name = fields.get(i); + if (name.startsWith(":")) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, streamId, "Trailer contains pseudo-header '" + name + "'"); + } + trailers.addHeaderCanonical(name, fields.get(i + 1)); + } + return trailers; + } + + static void validateContentLength(long expectedContentLength, long receivedContentLength, int streamId) + throws IOException { + if (expectedContentLength >= 0 && receivedContentLength != expectedContentLength) { + throw new H2Exception(ERROR_PROTOCOL_ERROR, + streamId, + "Content-Length mismatch: expected " + expectedContentLength + + " bytes, received " + receivedContentLength + " bytes"); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamBody.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamBody.java new file mode 100644 index 0000000000..4f2ed51d21 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamBody.java @@ -0,0 +1,196 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +/** + * Per-stream inbound body state backed by borrowed DATA-frame buffers. + * + *

The connection/reader side offers borrowed DATA-frame buffers directly to this queue. + * The response consumer side takes them and, when fully consumed, returns the + * underlying pooled buffer and releases flow-control credit through the supplied + * releaser. + */ +final class H2StreamBody { + interface ChunkReleaser { + int release(ByteBuffer buffer, int flowControlBytes); + } + + static final class ChunkSlot { + ByteBuffer data; + int flowControlBytes; + + void set(ByteBuffer data, int flowControlBytes) { + this.data = data; + this.flowControlBytes = flowControlBytes; + } + + void clear() { + this.data = null; + this.flowControlBytes = 0; + } + } + + private final ByteBuffer[] buffers; + private final int[] flowControlBytes; + private final ChunkReleaser releaser; + private int head; + private int tail; + private int size; + private boolean completed; + private IOException failure; + + H2StreamBody(int capacity, ChunkReleaser releaser) { + this.buffers = new ByteBuffer[capacity]; + this.flowControlBytes = new int[capacity]; + this.releaser = releaser; + } + + /** + * Enqueue a chunk for the consumer. When {@code signal} is true, wake the consumer + * (the typical case). When false, the producer is in a burst and a later call (or + * {@link #signal()}) will wake the consumer once the burst ends, avoiding notify/wait + * churn for intermediate frames. + */ + synchronized int offer(ByteBuffer data, int chunkFlowControlBytes, Consumer onClosed, boolean signal) { + while (failure == null && !completed && size == buffers.length) { + notifyAll(); + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + onClosed.accept(data); + return chunkFlowControlBytes; + } + } + if (failure != null || completed) { + onClosed.accept(data); + return chunkFlowControlBytes; + } + buffers[tail] = data; + flowControlBytes[tail] = chunkFlowControlBytes; + tail = (tail + 1) % buffers.length; + size++; + if (signal || size == buffers.length) { + notifyAll(); + } + return 0; + } + + /** Wake any consumer waiting on data. Called after a burst of {@link #offer} with {@code signal=false}. */ + synchronized void signal() { + notifyAll(); + } + + synchronized boolean take(ChunkSlot dest) throws IOException { + while (size == 0 && failure == null && !completed) { + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw interrupted(e); + } + } + if (failure != null) { + throw failure; + } + if (size == 0) { + return false; + } + dest.set(buffers[head], flowControlBytes[head]); + buffers[head] = null; + flowControlBytes[head] = 0; + head = (head + 1) % buffers.length; + size--; + notifyAll(); + return true; + } + + synchronized int takeBulk(ChunkSlot[] dest, int maxChunks) throws IOException { + while (size == 0 && failure == null && !completed) { + try { + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw interrupted(e); + } + } + if (failure != null) { + throw failure; + } + if (size == 0) { + return -1; + } + + int drained = 0; + while (drained < maxChunks && size > 0) { + dest[drained].set(buffers[head], flowControlBytes[head]); + buffers[head] = null; + flowControlBytes[head] = 0; + head = (head + 1) % buffers.length; + size--; + drained++; + } + notifyAll(); + return drained; + } + + synchronized void complete() { + completed = true; + notifyAll(); + } + + synchronized void fail(IOException error) { + failure = error; + notifyAll(); + } + + synchronized boolean isEmpty() { + return size == 0; + } + + /** + * True only once the producer has signalled end-of-body ({@link #complete()}) AND no chunk is + * queued. Unlike {@link #isEmpty()}, this never reports empty during the window between the + * reader thread setting END_STREAM and offering the trailing DATA chunk, so it is safe for the + * empty-response fast path in {@link H2Exchange#responseBody()}. + */ + synchronized boolean isCompletedEmpty() { + return completed && size == 0; + } + + synchronized int close() { + completed = true; + int released = 0; + while (size > 0) { + ByteBuffer data = buffers[head]; + int chunkFlowControlBytes = flowControlBytes[head]; + buffers[head] = null; + flowControlBytes[head] = 0; + released += releaser.release(data, chunkFlowControlBytes); + head = (head + 1) % buffers.length; + size--; + } + notifyAll(); + return released; + } + + /** + * Build the exception thrown when a consumer is interrupted waiting for response data. Uses + * {@link InterruptedIOException} (not a plain {@link IOException}) so callers (e.g. those composing + * under structured concurrency) can distinguish cancellation from a transport/server failure. The + * interrupt status is restored by the caller before this is thrown. + */ + private static InterruptedIOException interrupted(InterruptedException cause) { + var e = new InterruptedIOException("Interrupted waiting for response data"); + e.initCause(cause); + return e; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamRequestBody.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamRequestBody.java new file mode 100644 index 0000000000..a69e4c9ec9 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamRequestBody.java @@ -0,0 +1,88 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.ReadableByteChannel; +import java.util.function.Supplier; +import software.amazon.smithy.java.io.datastream.DataStream; + +/** + * Per-stream outbound body state. + * + *

Owns the pooled request-body staging buffer and the stream-facing output + * stream. This keeps upload-specific buffer ownership local to the stream + * instead of spreading it across {@link H2Exchange} and {@link H2DataOutputStream}. + */ +final class H2StreamRequestBody { + private static final int DIRECT_REPLAYABLE_UPLOAD_LIMIT = 8 * 1024 * 1024; + + private final H2Exchange exchange; + private final H2Muxer muxer; + private final Runnable onRequestStreamClosed; + private final Supplier endStreamSent; + private volatile OutputStream requestOut; + + H2StreamRequestBody( + H2Exchange exchange, + H2Muxer muxer, + Runnable onRequestStreamClosed, + Supplier endStreamSent + ) { + this.exchange = exchange; + this.muxer = muxer; + this.onRequestStreamClosed = onRequestStreamClosed; + this.endStreamSent = endStreamSent; + } + + synchronized OutputStream outputStream() { + if (requestOut == null) { + requestOut = endStreamSent.get() + ? new H2DataOutputStream(exchange, muxer, 0, onRequestStreamClosed) + : new H2DataOutputStream(exchange, muxer, muxer.getRemoteMaxFrameSize(), onRequestStreamClosed); + } + return requestOut; + } + + void writeRequestBody(DataStream body) throws IOException { + if (body == null || body.contentLength() == 0) { + outputStream().close(); + return; + } + + if (body.isReplayable() && body.hasKnownLength() && body.contentLength() <= Integer.MAX_VALUE) { + try { + if (body.contentLength() <= DIRECT_REPLAYABLE_UPLOAD_LIMIT) { + exchange.writeReplayableBody(body.asByteBuffer(), true); + } else { + try (ReadableByteChannel channel = body.asChannel()) { + exchange.writeChannelData(channel, body.contentLength(), true); + } + } + } finally { + onRequestStreamClosed.run(); + body.close(); + } + return; + } + + try (OutputStream out = outputStream()) { + // Use writeTo, not asInputStream().transferTo: a body can flush per message via writeTo (event + // streams send each event as its own DATA frame). Default writeTo is transferTo, so bulk bodies + // are unchanged. close() flushes any remainder and sends END_STREAM. + body.writeTo(out); + } finally { + body.close(); + } + } + + synchronized void closeIfOpen() throws IOException { + if (requestOut != null && !endStreamSent.get()) { + requestOut.close(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamState.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamState.java new file mode 100644 index 0000000000..96abee6a94 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/H2StreamState.java @@ -0,0 +1,358 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +/** + * Thread-safe packed state for an HTTP/2 stream. + * + *

Encapsulates stream state machine, read state, status code, and flags in a single 32-bit integer. + * All state transitions use CAS operations for thread safety between the reader thread (which delivers + * response data) and the user's virtual thread (which reads the response). + * + *

Bit Layout (32 bits total)

+ *
+ * [0-9]   (10 bits): StatusCode (0-1023). 0 means "not set" (-1 logic)
+ * [10]    (1 bit)  : ResponseHeadersReceived
+ * [11]    (1 bit)  : EndStreamReceived
+ * [12]    (1 bit)  : EndStreamSent
+ * [13-15] (3 bits) : ReadState (4 states, capacity for 8)
+ * [16-19] (4 bits) : StreamState (5 states, capacity for 16)
+ * [20-31] (12 bits): Reserved
+ * 
+ * + *

Stream States (RFC 9113 Section 5.1)

+ *
    + *
  • IDLE: Initial state before HEADERS sent
  • + *
  • OPEN: Both sides can send data
  • + *
  • HALF_CLOSED_LOCAL: We sent END_STREAM, waiting for response
  • + *
  • HALF_CLOSED_REMOTE: They sent END_STREAM, we can still send
  • + *
  • CLOSED: Both sides done
  • + *
+ * + *

Read States

+ *
    + *
  • WAITING: Waiting for response headers
  • + *
  • READING: Response headers received, reading body
  • + *
  • DONE: Response body complete (END_STREAM received)
  • + *
  • ERROR: An error occurred
  • + *
+ */ +final class H2StreamState { + + private static final int MASK_STATUS_CODE = 0x3FF; // 10 bits + private static final int FLAG_HEADERS_RECEIVED = 1 << 10; + private static final int FLAG_END_STREAM_RX = 1 << 11; + private static final int FLAG_END_STREAM_TX = 1 << 12; + + // ReadState constants (shift 13, 3 bits) + private static final int SHIFT_READ_STATE = 13; + private static final int MASK_READ_STATE = 0x7 << SHIFT_READ_STATE; + + // StreamState constants (shift 16, 4 bits) + private static final int SHIFT_STREAM_STATE = 16; + private static final int MASK_STREAM_STATE = 0xF << SHIFT_STREAM_STATE; + + /** Read state: waiting for response headers. */ + static final int RS_WAITING = 0; + /** Read state: response headers received, reading body. */ + static final int RS_READING = 1; + /** Read state: response body complete (END_STREAM received). */ + static final int RS_DONE = 2; + /** Read state: an error occurred. */ + static final int RS_ERROR = 3; + /** Stream state: initial state before HEADERS sent. */ + static final int SS_IDLE = 0; + /** Stream state: both sides can send data. */ + static final int SS_OPEN = 1; + /** Stream state: we sent END_STREAM, waiting for response. */ + static final int SS_HALF_CLOSED_LOCAL = 2; + /** Stream state: they sent END_STREAM, we can still send. */ + static final int SS_HALF_CLOSED_REMOTE = 3; + /** Stream state: both sides done. */ + static final int SS_CLOSED = 4; + + /** CAS VarHandle */ + private static final VarHandle STATE_HANDLE; + + static { + try { + STATE_HANDLE = MethodHandles.lookup().findVarHandle(H2StreamState.class, "packedState", int.class); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + // Initial: SS_IDLE, RS_WAITING, no flags, status=0 + @SuppressWarnings("FieldMayBeFinal") // it's mutated with a VarHandle + private volatile int packedState = (SS_IDLE << SHIFT_STREAM_STATE) | (RS_WAITING << SHIFT_READ_STATE); + + /** + * Get the current read state. + * + * @return one of RS_WAITING, RS_READING, RS_DONE, RS_ERROR + */ + int getReadState() { + return (packedState & MASK_READ_STATE) >> SHIFT_READ_STATE; + } + + /** + * Get the current stream state. + * + * @return one of SS_IDLE, SS_OPEN, SS_HALF_CLOSED_LOCAL, SS_HALF_CLOSED_REMOTE, SS_CLOSED + */ + int getStreamState() { + return (packedState & MASK_STREAM_STATE) >> SHIFT_STREAM_STATE; + } + + /** + * Check if response headers have been received. + * + * @return true if response headers (final, not 1xx) have been received + */ + boolean isResponseHeadersReceived() { + return (packedState & FLAG_HEADERS_RECEIVED) != 0; + } + + /** + * Check if END_STREAM has been received from the remote peer. + * + * @return true if END_STREAM was received + */ + boolean isEndStreamReceived() { + return (packedState & FLAG_END_STREAM_RX) != 0; + } + + /** + * Check if END_STREAM has been sent to the remote peer. + * + * @return true if END_STREAM was sent + */ + boolean isEndStreamSent() { + return (packedState & FLAG_END_STREAM_TX) != 0; + } + + /** + * Get the HTTP status code from the response. + * + * @return the status code, or -1 if not yet received + */ + int getStatusCode() { + int code = packedState & MASK_STATUS_CODE; + return code == 0 ? -1 : code; // 0 means not set + } + + /** + * Atomically set response headers received with status code. + * Transitions read state from WAITING to READING if appropriate. + * + * @param statusCode the HTTP status code (100-599) + */ + void setResponseHeadersReceived(int statusCode) { + for (;;) { + int current = packedState; + int newState = current; + + // Set status code (clear old, set new) + newState &= ~MASK_STATUS_CODE; + newState |= (statusCode & MASK_STATUS_CODE); + + // Set headers received flag + newState |= FLAG_HEADERS_RECEIVED; + + // Transition read state: WAITING -> READING + int readState = (current & MASK_READ_STATE) >> SHIFT_READ_STATE; + if (readState == RS_WAITING) { + newState &= ~MASK_READ_STATE; + newState |= (RS_READING << SHIFT_READ_STATE); + } + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically mark end stream received. + * Updates read state to DONE and stream state appropriately. + */ + void markEndStreamReceived() { + for (;;) { + int current = packedState; + int newState = current | FLAG_END_STREAM_RX; + + // Set read state to DONE + newState &= ~MASK_READ_STATE; + newState |= (RS_DONE << SHIFT_READ_STATE); + + // Update stream state + int currentSS = (current & MASK_STREAM_STATE) >> SHIFT_STREAM_STATE; + int newSS = computeEndStreamTransition(currentSS, true); + if (newSS >= 0) { + newState &= ~MASK_STREAM_STATE; + newState |= (newSS << SHIFT_STREAM_STATE); + } + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically mark end stream sent. + * Updates stream state appropriately. + */ + void markEndStreamSent() { + for (;;) { + int current = packedState; + if ((current & FLAG_END_STREAM_TX) != 0) { + return; // Already set + } + + int newState = current | FLAG_END_STREAM_TX; + + // Update stream state + int currentSS = (current & MASK_STREAM_STATE) >> SHIFT_STREAM_STATE; + int newSS = computeEndStreamTransition(currentSS, false); + if (newSS >= 0) { + newState &= ~MASK_STREAM_STATE; + newState |= (newSS << SHIFT_STREAM_STATE); + } + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically set read state to DONE. + */ + void setReadStateDone() { + for (;;) { + int current = packedState; + int newState = current; + newState &= ~MASK_READ_STATE; + newState |= (RS_DONE << SHIFT_READ_STATE); + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically set stream state to CLOSED. + */ + void setStreamStateClosed() { + for (;;) { + int current = packedState; + int newState = current; + newState &= ~MASK_STREAM_STATE; + newState |= (SS_CLOSED << SHIFT_STREAM_STATE); + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically set error state: endStreamReceived flag + readState=ERROR. + * Does NOT update stream state (unlike markEndStreamReceived). + * Used for error paths where we want to signal the consumer without + * affecting protocol state machine. + */ + void setErrorState() { + setEndStreamFlagAndReadState(RS_ERROR); + } + + /** + * Atomically set endStreamReceived flag and readState=DONE. + * Does NOT update stream state - used by enqueueData where we're just + * recording that we've received all data, but stream state machine + * transitions happen elsewhere (handleHeadersEvent). + */ + void setEndStreamReceivedFlag() { + setEndStreamFlagAndReadState(RS_DONE); + } + + /** + * Called when headers are encoded and about to be sent. + * Atomically transitions stream state and optionally marks end stream sent. + * + * @param endStream true if END_STREAM flag is set on the HEADERS frame + */ + void onHeadersEncoded(boolean endStream) { + for (;;) { + int current = packedState; + int newState = current; + + if (endStream) { + newState |= FLAG_END_STREAM_TX; + newState &= ~MASK_STREAM_STATE; + newState |= (SS_HALF_CLOSED_LOCAL << SHIFT_STREAM_STATE); + } else { + newState &= ~MASK_STREAM_STATE; + newState |= (SS_OPEN << SHIFT_STREAM_STATE); + } + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Atomically set endStreamReceived flag and the specified read state. + * Does NOT update stream state - used where we want to signal the consumer + * without affecting the H2 protocol state machine. + * + * @param readState the read state to set (RS_DONE or RS_ERROR) + */ + private void setEndStreamFlagAndReadState(int readState) { + for (;;) { + int current = packedState; + int newState = current | FLAG_END_STREAM_RX; + newState &= ~MASK_READ_STATE; + newState |= (readState << SHIFT_READ_STATE); + + if (STATE_HANDLE.compareAndSet(this, current, newState)) { + return; + } + } + } + + /** + * Compute the new stream state after an end-stream event. + * + * @param currentStreamState current stream state + * @param isReceived true if end-stream received, false if end-stream sent + * @return the new stream state, or -1 if no change needed + */ + private static int computeEndStreamTransition(int currentStreamState, boolean isReceived) { + if (isReceived) { + // End stream received: OPEN→HALF_CLOSED_REMOTE, HALF_CLOSED_LOCAL→CLOSED + if (currentStreamState == SS_OPEN) { + return SS_HALF_CLOSED_REMOTE; + } else if (currentStreamState == SS_HALF_CLOSED_LOCAL) { + return SS_CLOSED; + } + } else { + // End stream sent: OPEN→HALF_CLOSED_LOCAL, HALF_CLOSED_REMOTE→CLOSED + if (currentStreamState == SS_OPEN) { + return SS_HALF_CLOSED_LOCAL; + } else if (currentStreamState == SS_HALF_CLOSED_REMOTE) { + return SS_CLOSED; + } + } + return -1; // No change + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackDecoder.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackDecoder.java new file mode 100644 index 0000000000..4355fb51e9 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackDecoder.java @@ -0,0 +1,285 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import software.amazon.smithy.java.http.api.HeaderName; + +/** + * HPACK decoder for HTTP/2 header decompression (RFC 7541). + * + *

Thread safety: This class is not thread-safe. Each HTTP/2 connection should have + * its own decoder instance to maintain dynamic table state. + */ +final class HpackDecoder { + + private static final int DEFAULT_MAX_TABLE_SIZE = 4096; + private static final int DEFAULT_MAX_HEADER_LIST_SIZE = 8192; + + private final DynamicTable dynamicTable; + private final int maxHeaderListSize; + private int maxTableSize; + + /** Current position during decoding, reset at start of each decode call. */ + private int decodePos; + /** End of current decode region. */ + private int limit; + + /** + * Create a decoder with default limits (4096 byte table, 8192 byte header list). + */ + public HpackDecoder() { + this(DEFAULT_MAX_TABLE_SIZE, DEFAULT_MAX_HEADER_LIST_SIZE); + } + + /** + * Create a decoder with the given maximum dynamic table size. + * + * @param maxTableSize maximum dynamic table size in bytes + */ + public HpackDecoder(int maxTableSize) { + this(maxTableSize, DEFAULT_MAX_HEADER_LIST_SIZE); + } + + /** + * Create a decoder with the given limits. + * + * @param maxTableSize maximum dynamic table size in bytes + * @param maxHeaderListSize maximum size of decoded header list + */ + public HpackDecoder(int maxTableSize, int maxHeaderListSize) { + this.dynamicTable = new DynamicTable(maxTableSize); + this.maxTableSize = maxTableSize; + this.maxHeaderListSize = maxHeaderListSize; + } + + /** + * Set the maximum dynamic table size. + * + * @param maxSize new maximum size in bytes + */ + public void setMaxTableSize(int maxSize) { + this.maxTableSize = maxSize; + dynamicTable.setMaxSize(maxSize); + } + + /** + * Decode a header block. + * + * @param data the HPACK-encoded header block + * @return flat list of headers: [name0, value0, name1, value1, ...] + * @throws IOException if decoding fails + */ + public List decode(byte[] data) throws IOException { + return decode(data, 0, data.length); + } + + /** + * Decode a header block. + * + * @param data buffer containing HPACK-encoded header block + * @param offset start offset in buffer + * @param length number of bytes to decode + * @return flat list of headers: [name0, value0, name1, value1, ...] + * @throws IOException if decoding fails + */ + public List decode(byte[] data, int offset, int length) throws IOException { + if (length == 0) { + return List.of(); + } + + // ~12 headers * 2 = 24 + List headers = new ArrayList<>(24); + decodePos = offset; + limit = offset + length; + int totalSize = 0; + boolean headerFieldSeen = false; + + while (decodePos < limit) { + int b = data[decodePos] & 0xFF; + + String name, value; + if ((b & 0x80) != 0) { + // Indexed representation: 1xxxxxxx + int index = decodeInteger(data, 7); + if (index <= 0) { + throw new IOException("Invalid HPACK index: " + index); + } else if (index <= StaticTable.SIZE) { + name = StaticTable.getName(index); + value = StaticTable.getValue(index); + } else { + try { + name = dynamicTable.getName(index); + value = dynamicTable.getValue(index); + } catch (IndexOutOfBoundsException e) { + throw new IOException(e.getMessage(), e); + } + } + headerFieldSeen = true; + } else if ((b & 0x40) != 0) { + // Literal with indexing: 01xxxxxx + int nameIndex = decodeInteger(data, 6); + name = nameIndex > 0 ? getIndexedName(nameIndex) : decodeHeaderName(data); + value = decodeString(data); + dynamicTable.add(name, value); + headerFieldSeen = true; + } else if ((b & 0x20) != 0) { + // Dynamic table size update: 001xxxxx + // RFC 7541 Section 4.2: "This dynamic table size update MUST occur at the beginning of the first + // header block following the change to the dynamic table size" + if (headerFieldSeen) { + throw new IOException("Dynamic table size update MUST occur at beginning of header block"); + } + int newSize = decodeInteger(data, 5); + if (newSize > maxTableSize) { + throw new IOException( + "Dynamic table size update " + newSize + " exceeds configured maximum " + maxTableSize); + } + dynamicTable.setMaxSize(newSize); + continue; + } else { + // Literal never indexed (0001xxxx) or without indexing (0000xxxx) + int nameIndex = decodeInteger(data, 4); + name = nameIndex > 0 ? getIndexedName(nameIndex) : decodeHeaderName(data); + value = decodeString(data); + headerFieldSeen = true; + } + + // Check header list size + totalSize += name.length() + value.length() + 32; + if (totalSize > maxHeaderListSize) { + throw new IOException("Header list exceeds maximum size: " + totalSize + " > " + maxHeaderListSize); + } + + headers.add(name); + headers.add(value); + } + + return headers; + } + + /** + * Get a header name from the indexed tables. + * + * @param index table index (1-61 for static, 62+ for dynamic) + * @return header name + * @throws IOException if index is invalid + */ + private String getIndexedName(int index) throws IOException { + if (index <= 0) { + throw new IOException("Invalid HPACK name index: " + index); + } + try { + return index <= StaticTable.SIZE ? StaticTable.getName(index) : dynamicTable.getName(index); + } catch (IndexOutOfBoundsException e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * Decode an integer with the given prefix size. Updates decodePos and returns the decoded value. + * + * @param data buffer containing encoded integer + * @param prefixBits number of prefix bits (1-8) + * @return decoded integer value + * @throws IOException if integer is incomplete or overflows + */ + private int decodeInteger(byte[] data, int prefixBits) throws IOException { + if (decodePos >= limit) { + throw new IOException("Incomplete HPACK integer"); + } + + int maxPrefix = (1 << prefixBits) - 1; + int value = data[decodePos] & maxPrefix; + decodePos++; + + if (value < maxPrefix) { + return value; + } + + int shift = 0; + int b; + do { + if (decodePos >= limit) { + throw new IOException("Incomplete HPACK integer"); + } + b = data[decodePos++] & 0xFF; + if (shift >= 28) { + throw new IOException("HPACK integer overflow"); + } + value += (b & 0x7F) << shift; + shift += 7; + } while ((b & 0x80) != 0); + + return value; + } + + /** + * Decode a string literal. + * Updates decodePos and returns the decoded string. + * + * @param data buffer containing encoded string + * @return decoded string + * @throws IOException if string is incomplete or invalid + */ + private String decodeString(byte[] data) throws IOException { + if (decodePos >= limit) { + throw new IOException("Incomplete HPACK string"); + } + + boolean isHuffmanEncoded = (data[decodePos] & 0x80) != 0; + int length = decodeStringLength(data); + int start = decodePos; + decodePos += length; + return isHuffmanEncoded + ? Huffman.decode(data, start, length) + : new String(data, start, length, StandardCharsets.ISO_8859_1); + } + + private int decodeStringLength(byte[] data) throws IOException { + int length = decodeInteger(data, 7); + if (decodePos + length > limit) { + throw new IOException("HPACK string length exceeds buffer"); + } + return length; + } + + /** + * Decode a header name string with validation and canonicalization. + * + *

Validates that literal names do not contain uppercase characters, then canonicalizes via {@link HeaderName}. + * + * @param data buffer containing encoded name + * @return canonical header name + * @throws IOException if validation fails or decoding fails + */ + private String decodeHeaderName(byte[] data) throws IOException { + if (decodePos >= limit) { + throw new IOException("Incomplete HPACK string"); + } + + boolean isHuffmanEncoded = (data[decodePos] & 0x80) != 0; + int length = decodeStringLength(data); + int start = decodePos; + decodePos += length; + + if (isHuffmanEncoded) { + return Huffman.decodeHeaderName(data, start, length); + } + + for (int i = 0; i < length; i++) { + byte b = data[start + i]; + if (b >= 'A' && b <= 'Z') { + throw new IOException("Header name contains uppercase"); + } + } + + return HeaderName.canonicalize(data, start, length); + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackEncoder.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackEncoder.java new file mode 100644 index 0000000000..cfda655ed9 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/HpackEncoder.java @@ -0,0 +1,268 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; +import software.amazon.smithy.java.io.ByteBufferOutputStream; + +/** + * HPACK encoder for HTTP/2 header compression (RFC 7541). + * + *

Thread safety: This class is NOT thread-safe. Each HTTP/2 connection should have its own encoder instance. + */ +final class HpackEncoder { + + // Headers that should never be indexed (sensitive data) + private static final Set NEVER_INDEX_HEADERS = Set.of( + "authorization", + "cookie", + "proxy-authorization", + "set-cookie"); + + // HPACK representation type prefixes (RFC 7541 Section 6) + private static final int PREFIX_INDEXED = 0x80; // 1xxxxxxx + private static final int PREFIX_LITERAL_INDEXED = 0x40; // 01xxxxxx + private static final int PREFIX_SIZE_UPDATE = 0x20; // 001xxxxx + private static final int PREFIX_LITERAL_NEVER = 0x10; // 0001xxxx + + private static final int DEFAULT_MAX_TABLE_SIZE = 4096; + + private final DynamicTable dynamicTable; + private final boolean useHuffman; + + // Track pending table size updates to emit at start of next header block (RFC 7541 Section 4.2). + // If multiple size changes occur before a header block, we must emit the minimum reached + // and then the final size, to ensure the decoder evicts the same entries we did. + private int pendingTableSizeUpdate = -1; + private int minPendingTableSize = -1; + + // Reusable scratch buffer for string encoding to avoid per-string allocation. + // Typical header values are < 256 bytes; buffer grows if needed. + private byte[] stringBuf = new byte[256]; + + /** + * Create an encoder with default limits (4096 byte table) and Huffman encoding enabled. + */ + public HpackEncoder() { + this(DEFAULT_MAX_TABLE_SIZE, true); + } + + /** + * Create an encoder with the given maximum dynamic table size and Huffman encoding enabled. + * + * @param maxTableSize maximum dynamic table size in bytes + */ + public HpackEncoder(int maxTableSize) { + this(maxTableSize, true); + } + + /** + * Create an encoder with the given maximum dynamic table size. + * + * @param maxTableSize maximum dynamic table size in bytes + * @param useHuffman whether to use Huffman encoding for strings + */ + public HpackEncoder(int maxTableSize, boolean useHuffman) { + this.dynamicTable = new DynamicTable(maxTableSize); + this.useHuffman = useHuffman; + } + + /** + * Set the maximum dynamic table size. + * + *

This should be called when receiving a SETTINGS frame with SETTINGS_HEADER_TABLE_SIZE. + * Per RFC 7541 Section 4.2, the encoder MUST signal the change to the decoder at the start of the next + * header block (only if the size actually changed). + * + * @param maxSize new maximum size in bytes + */ + public void setMaxTableSize(int maxSize) { + int currentMaxSize = dynamicTable.maxSize(); + + if (maxSize != currentMaxSize) { + dynamicTable.setMaxSize(maxSize); + // Track the minimum size reached since last header block + if (pendingTableSizeUpdate != -1) { + minPendingTableSize = Math.min(minPendingTableSize, maxSize); + } else { + minPendingTableSize = maxSize; + } + pendingTableSizeUpdate = maxSize; + } + } + + /** + * Emit any pending dynamic table size update. + * + *

Per RFC 7541 Section 4.2, when SETTINGS_HEADER_TABLE_SIZE is received, the encoder MUST signal the change + * at the start of the next header block by emitting a dynamic table size update instruction. + * + *

This method MUST be called once at the start of each header block (before encoding any headers). + * + * @param out output stream to write the update to + * @throws IOException if writing fails + */ + public void beginHeaderBlock(OutputStream out) throws IOException { + if (pendingTableSizeUpdate >= 0) { + // RFC 7541 Section 4.2: If size was reduced then raised, emit the minimum first + // to ensure the decoder evicts the same entries we did. + if (minPendingTableSize < pendingTableSizeUpdate) { + encodeInteger(out, minPendingTableSize, 5, PREFIX_SIZE_UPDATE); + } + encodeInteger(out, pendingTableSizeUpdate, 5, PREFIX_SIZE_UPDATE); + pendingTableSizeUpdate = -1; + minPendingTableSize = -1; + } + } + + /** + * Encode a single header field. + * + * @param out output stream to write encoded bytes + * @param name header name (lowercase) + * @param value header value + * @param sensitive whether this header contains sensitive data + * @throws IOException if encoding fails + */ + public void encodeHeader(OutputStream out, String name, String value, boolean sensitive) throws IOException { + // Sensitive headers should never be indexed + if (sensitive || NEVER_INDEX_HEADERS.contains(name)) { + encodeLiteralNeverIndexed(out, name, value); + return; + } + + // Try to find full match in static table + int staticIndex = StaticTable.findFullMatch(name, value); + if (staticIndex > 0) { + encodeIndexed(out, staticIndex); + return; + } + + // Try to find full match in dynamic table + int dynamicIndex = dynamicTable.findFullMatch(name, value); + if (dynamicIndex > 0) { + encodeIndexed(out, dynamicIndex); + return; + } + + // Try to find name match for literal with indexing + int nameIndex = StaticTable.findNameMatch(name); + if (nameIndex < 0) { + nameIndex = dynamicTable.findNameMatch(name); + } + + // Encode as literal with indexing (adds to dynamic table) + encodeLiteralWithIndexing(out, nameIndex, name, value); + + // Add to dynamic table + dynamicTable.add(name, value); + } + + /** + * Encode a header using indexed representation. + * Format: 1xxxxxxx (7-bit prefix) + */ + private void encodeIndexed(OutputStream out, int index) throws IOException { + encodeInteger(out, index, 7, PREFIX_INDEXED); + } + + /** + * Encode a header as literal with indexing. Format: 01xxxxxx (6-bit prefix for index) + */ + private void encodeLiteralWithIndexing(OutputStream out, int nameIndex, String name, String value) + throws IOException { + if (nameIndex > 0) { + // Indexed name + encodeInteger(out, nameIndex, 6, PREFIX_LITERAL_INDEXED); + } else { + // New name + out.write(PREFIX_LITERAL_INDEXED); + encodeString(out, name); + } + encodeString(out, value); + } + + /** + * Encode a header as literal never indexed. Format: 0001xxxx (4-bit prefix for index) + */ + private void encodeLiteralNeverIndexed(OutputStream out, int nameIndex, String name, String value) + throws IOException { + if (nameIndex > 0) { + encodeInteger(out, nameIndex, 4, PREFIX_LITERAL_NEVER); + } else { + out.write(PREFIX_LITERAL_NEVER); + encodeString(out, name); + } + encodeString(out, value); + } + + private void encodeLiteralNeverIndexed(OutputStream out, String name, String value) throws IOException { + int nameIndex = StaticTable.findNameMatch(name); + if (nameIndex < 0) { + nameIndex = dynamicTable.findNameMatch(name); + } + encodeLiteralNeverIndexed(out, Math.max(nameIndex, 0), name, value); + } + + /** + * Encode an integer with the given prefix size. RFC 7541 Section 5.1 + */ + private void encodeInteger(OutputStream out, int value, int prefixBits, int prefix) throws IOException { + int maxPrefix = (1 << prefixBits) - 1; + + if (value < maxPrefix) { + out.write(prefix | value); + } else { + out.write(prefix | maxPrefix); + value -= maxPrefix; + while (value >= 128) { + out.write((value & 0x7F) | 0x80); + value >>= 7; + } + out.write(value); + } + } + + /** + * Encode a string, using Huffman encoding if it saves space. + */ + @SuppressWarnings("deprecation") + private void encodeString(OutputStream out, String str) throws IOException { + int len = str.length(); + + if (useHuffman) { + // Need bytes in scratch buffer to calculate Huffman length + if (len > stringBuf.length) { + stringBuf = new byte[len]; + } + str.getBytes(0, len, stringBuf, 0); + + // Only use Huffman if it saves space. + int huffmanLen = Huffman.encodedLength(stringBuf, 0, len); + if (huffmanLen < len) { + encodeInteger(out, huffmanLen, 7, 0x80); // H=1 + Huffman.encode(stringBuf, 0, len, out); + } else { + encodeInteger(out, len, 7, 0x00); // H=0 + out.write(stringBuf, 0, len); + } + } else { + // Raw encoding, use optimized path for ByteBufferOutputStream if available. + encodeInteger(out, len, 7, 0x00); // H=0 + if (out instanceof ByteBufferOutputStream bbos) { + bbos.writeAscii(str); + } else { + if (len > stringBuf.length) { + stringBuf = new byte[len]; + } + str.getBytes(0, len, stringBuf, 0); + out.write(stringBuf, 0, len); + } + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/Huffman.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/Huffman.java new file mode 100644 index 0000000000..74356f39b4 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/Huffman.java @@ -0,0 +1,792 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import software.amazon.smithy.java.http.api.HeaderName; + +/** + * HPACK Huffman encoding/decoding from RFC 7541 Appendix B. + * + *

This implementation uses table-driven encoding and a finite state machine + * for decoding, optimized for the HTTP/2 header compression use case. + */ +final class Huffman { + + private Huffman() {} + + /** + * Huffman codes for each byte value (0-255), from RFC 7541 Appendix B. + */ + private static final int[] CODES = { + 0x1ff8, + 0x7fffd8, + 0xfffffe2, + 0xfffffe3, + 0xfffffe4, + 0xfffffe5, + 0xfffffe6, + 0xfffffe7, + 0xfffffe8, + 0xffffea, + 0x3ffffffc, + 0xfffffe9, + 0xfffffea, + 0x3ffffffd, + 0xfffffeb, + 0xfffffec, + 0xfffffed, + 0xfffffee, + 0xfffffef, + 0xffffff0, + 0xffffff1, + 0xffffff2, + 0x3ffffffe, + 0xffffff3, + 0xffffff4, + 0xffffff5, + 0xffffff6, + 0xffffff7, + 0xffffff8, + 0xffffff9, + 0xffffffa, + 0xffffffb, + 0x14, + 0x3f8, + 0x3f9, + 0xffa, + 0x1ff9, + 0x15, + 0xf8, + 0x7fa, + 0x3fa, + 0x3fb, + 0xf9, + 0x7fb, + 0xfa, + 0x16, + 0x17, + 0x18, + 0x0, + 0x1, + 0x2, + 0x19, + 0x1a, + 0x1b, + 0x1c, + 0x1d, + 0x1e, + 0x1f, + 0x5c, + 0xfb, + 0x7ffc, + 0x20, + 0xffb, + 0x3fc, + 0x1ffa, + 0x21, + 0x5d, + 0x5e, + 0x5f, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6a, + 0x6b, + 0x6c, + 0x6d, + 0x6e, + 0x6f, + 0x70, + 0x71, + 0x72, + 0xfc, + 0x73, + 0xfd, + 0x1ffb, + 0x7fff0, + 0x1ffc, + 0x3ffc, + 0x22, + 0x7ffd, + 0x3, + 0x23, + 0x4, + 0x24, + 0x5, + 0x25, + 0x26, + 0x27, + 0x6, + 0x74, + 0x75, + 0x28, + 0x29, + 0x2a, + 0x7, + 0x2b, + 0x76, + 0x2c, + 0x8, + 0x9, + 0x2d, + 0x77, + 0x78, + 0x79, + 0x7a, + 0x7b, + 0x7ffe, + 0x7fc, + 0x3ffd, + 0x1ffd, + 0xffffffc, + 0xfffe6, + 0x3fffd2, + 0xfffe7, + 0xfffe8, + 0x3fffd3, + 0x3fffd4, + 0x3fffd5, + 0x3fffd6, + 0x3fffd7, + 0x3fffd8, + 0x3fffd9, + 0x3fffda, + 0x3fffdb, + 0x3fffdc, + 0x3fffdd, + 0x3fffde, + 0x3fffdf, + 0x3fffe0, + 0x3fffe1, + 0x3fffe2, + 0x3fffe3, + 0x3fffe4, + 0x3fffe5, + 0x3fffe6, + 0x3fffe7, + 0x3fffe8, + 0x3fffe9, + 0x3fffea, + 0x3fffeb, + 0xffffec, + 0x3fffec, + 0x3fffed, + 0x3fffee, + 0x3fffef, + 0x3ffff0, + 0x3ffff1, + 0x3ffff2, + 0x3ffff3, + 0x3ffff4, + 0x3ffff5, + 0x3ffff6, + 0x3ffff7, + 0x3ffff8, + 0x3ffff9, + 0x3ffffa, + 0x3ffffb, + 0xfffffb, + 0xfffffc, + 0xfffffd, + 0xfffffe, + 0xffffff, + 0x1ffffec, + 0x1ffffed, + 0x1ffffee, + 0x1ffffef, + 0x1fffff0, + 0x1fffff1, + 0x1fffff2, + 0x1fffff3, + 0x1fffff4, + 0x1fffff5, + 0x1fffff6, + 0x1fffff7, + 0x1fffff8, + 0x1fffff9, + 0x1fffffa, + 0x1fffffb, + 0x1fffffc, + 0x1fffffd, + 0x1fffffe, + 0x1ffffff, + 0x3fffffc, + 0x3fffffd, + 0x3fffffe, + 0x3ffffff, + 0x7fffffc, + 0x7fffffd, + 0x7fffffe, + 0x7ffffff, + 0xffffffc, + 0xffffffd, + 0xffffffe, + 0xfffffff, + 0x10000000, + 0x10000001, + 0x10000002, + 0x10000003, + 0x10000004, + 0x10000005, + 0x10000006, + 0x10000007, + 0x10000008, + 0x10000009, + 0x1000000a, + 0x1000000b, + 0x1000000c, + 0x1000000d, + 0x1000000e, + 0x1000000f, + 0x10000010, + 0x10000011, + 0x10000012, + 0x10000013, + 0x10000014, + 0x10000015, + 0x10000016, + 0x10000017, + 0x10000018, + 0x10000019, + 0x1000001a, + 0x1000001b, + 0x1000001c, + 0x1000001d, + 0x1000001e, + 0x1000001f, + 0x10000020, + 0x10000021, + 0x10000022, + 0x10000023, + 0x10000024, + 0x10000025, + 0x10000026, + 0x10000027, + 0x10000028, + 0x10000029, + 0x1000002a, + 0x1000002b, + 0x1000002c + }; + + /** + * Huffman code lengths (in bits) for each byte value (0-255), from RFC 7541 Appendix B. + */ + private static final byte[] LENGTHS = { + 13, + 23, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 24, + 30, + 28, + 28, + 30, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 30, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 6, + 10, + 10, + 12, + 13, + 6, + 8, + 11, + 10, + 10, + 8, + 11, + 8, + 6, + 6, + 6, + 5, + 5, + 5, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 7, + 8, + 15, + 6, + 12, + 10, + 13, + 6, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 8, + 7, + 8, + 13, + 19, + 13, + 14, + 6, + 15, + 5, + 6, + 5, + 6, + 5, + 6, + 6, + 6, + 5, + 7, + 7, + 6, + 6, + 6, + 5, + 6, + 7, + 6, + 5, + 5, + 6, + 7, + 7, + 7, + 7, + 7, + 15, + 11, + 14, + 13, + 28, + 20, + 22, + 20, + 20, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 24, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 24, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28 + }; + + // Decode flags + private static final int FLAG_EMIT = 0x01; // Emit a decoded byte + private static final int FLAG_ACCEPTED = 0x02; // Valid end state + private static final int FLAG_FAIL = 0x04; // Invalid sequence + + /** + * Huffman decoding table using finite state machine. + * Each entry is {next_state, flags, emitted_byte}. + * The table is indexed by (state << 4) | nibble. + * + *

This table was generated from the Huffman tree in RFC 7541. + * States 0-511 represent positions in the decoding tree (511 nodes max). + */ + private static final int[][] DECODE_TABLE = buildDecodeTable(); + + /** + * Encode bytes using Huffman coding directly to an output stream. + * + *

This avoids allocating an intermediate byte[] buffer. + * + * @param data the bytes to encode + * @param offset start offset in data + * @param length number of bytes to encode + * @param out the output stream to write to + * @throws IOException if writing fails + */ + static void encode(byte[] data, int offset, int length, OutputStream out) throws IOException { + long current = 0; + int bits = 0; + + int end = offset + length; + for (int i = offset; i < end; i++) { + int index = data[i] & 0xFF; + int code = CODES[index]; + int codeLength = LENGTHS[index]; + + current <<= codeLength; + current |= code; + bits += codeLength; + + while (bits >= 8) { + bits -= 8; + out.write((int) (current >> bits)); + } + } + + // Pad with EOS (all 1s) to byte boundary + if (bits > 0) { + out.write((int) ((current << (8 - bits)) | (0xFF >> bits))); + } + } + + /** + * Calculate the encoded length of a byte array region without actually encoding it. + * + * @param data the bytes to measure + * @param offset start offset in data + * @param length number of bytes to measure + * @return length in bytes when Huffman-encoded + */ + static int encodedLength(byte[] data, int offset, int length) { + int bits = 0; + int end = offset + length; + for (int i = offset; i < end; i++) { + bits += LENGTHS[data[i] & 0xFF]; + } + return (bits + 7) / 8; + } + + /** + * Decode Huffman-encoded bytes to a string. + * + * @param data the buffer containing Huffman-encoded bytes + * @param offset start offset in buffer + * @param length number of bytes to decode + * @return decoded string + * @throws IOException if decoding fails (invalid Huffman sequence) + */ + static String decode(byte[] data, int offset, int length) throws IOException { + // Safe: shortest HPACK Huffman code is 5 bits, so max expansion is 8/5 = 1.6x < 2x + byte[] buf = new byte[length * 2]; + int pos = decodeBytes(data, offset, length, false, buf); + return new String(buf, 0, pos, StandardCharsets.ISO_8859_1); + } + + /** + * Decode a Huffman-encoded header name, validating no uppercase and canonicalizing. + */ + static String decodeHeaderName(byte[] data, int offset, int length) throws IOException { + // Safe: shortest HPACK Huffman code is 5 bits, so max expansion is 8/5 = 1.6x < 2x + byte[] buf = new byte[length * 2]; + int pos = decodeBytes(data, offset, length, true, buf); + return HeaderName.canonicalize(buf, 0, pos); + } + + /** + * Decode Huffman-encoded bytes into the provided buffer. + * + * @param buf output buffer, must be at least {@code length * 2} bytes + * @return number of decoded bytes written to buf + */ + private static int decodeBytes(byte[] data, int offset, int length, boolean validateName, byte[] buf) + throws IOException { + assert buf.length >= length * 2 : "buffer too small for Huffman decode"; + int pos = 0; + int state = 0; + boolean accepted = true; + + for (int i = offset; i < offset + length; i++) { + int b = data[i] & 0xFF; + + // Process high nibble + int index = (state << 4) | (b >> 4); + state = DECODE_TABLE[index][0]; + int flags = DECODE_TABLE[index][1]; + + pos = processNibble(validateName, buf, pos, index, flags); + + // Process low nibble + index = (state << 4) | (b & 0x0F); + state = DECODE_TABLE[index][0]; + flags = DECODE_TABLE[index][1]; + + pos = processNibble(validateName, buf, pos, index, flags); + accepted = (flags & FLAG_ACCEPTED) != 0; + } + + if (!accepted) { + throw new IOException("Invalid Huffman encoding: incomplete sequence"); + } + + return pos; + } + + private static int processNibble(boolean validateName, byte[] buf, int pos, int index, int flags) + throws IOException { + if ((flags & FLAG_FAIL) != 0) { + throw new IOException("Invalid Huffman encoding"); + } + + if ((flags & FLAG_EMIT) != 0) { + byte emitted = (byte) DECODE_TABLE[index][2]; + if (validateName && emitted >= 'A' && emitted <= 'Z') { + throw new IOException("Header name contains uppercase"); + } + buf[pos++] = emitted; + } + + return pos; + } + + private static int[][] buildDecodeTable() { + // State machine with up to 512 states (Huffman tree has 511 nodes: 256 leaves + 255 internal) + int[][] table = new int[512 * 16][3]; + + // Initialize all entries to fail state + for (int[] row : table) { + row[1] = FLAG_FAIL; + } + + // Tree as parallel arrays: left[i] and right[i] are children of state i (-1 = none) + // symbol[i] is decoded symbol at state i (-1 = non-terminal) + int[] left = new int[512]; + int[] right = new int[512]; + int[] symbol = new int[512]; + Arrays.fill(left, -1); + Arrays.fill(right, -1); + Arrays.fill(symbol, -1); + int numStates = 1; // state 0 is root + + // Build tree + for (int sym = 0; sym < 256; sym++) { + int code = CODES[sym]; + int len = LENGTHS[sym]; + int state = 0; + for (int i = len - 1; i >= 0; i--) { + int bit = (code >> i) & 1; + int[] children = (bit == 0) ? left : right; + if (children[state] == -1) { + children[state] = numStates++; + } + state = children[state]; + } + symbol[state] = sym; + } + + // Build state transition table for each nibble (4 bits at a time) + for (int startState = 0; startState < numStates; startState++) { + for (int nibble = 0; nibble < 16; nibble++) { + int cur = startState; + int emitted = -1; + boolean failed = false; + + // Process 4 bits + for (int i = 3; i >= 0; i--) { + int bit = (nibble >> i) & 1; + cur = (bit == 0) ? left[cur] : right[cur]; + if (cur == -1) { + failed = true; + break; + } + if (symbol[cur] != -1) { + emitted = symbol[cur]; + cur = 0; // reset to root + } + } + + if (failed) { + continue; // already initialized to FAIL + } + + int idx = (startState << 4) | nibble; + table[idx][0] = cur; + table[idx][1] = (emitted >= 0 ? FLAG_EMIT : 0) + | (canBeEosPadded(cur, symbol, right) ? FLAG_ACCEPTED : 0); + table[idx][2] = Math.max(emitted, 0); + } + } + + return table; + } + + /** + * Check if a state can be valid EOS padding per RFC 7541. + * A state is accepted if following all 1-bits (right children) for up to 7 bits + * never reaches a terminal symbol. + */ + private static boolean canBeEosPadded(int state, int[] symbol, int[] right) { + // root is always accepted + if (state == 0) { + return true; + } + + for (int i = 0; i < 7; i++) { + if (state == -1) { + return false; + } else if (symbol[state] != -1) { + return false; // would decode a symbol - invalid padding + } + state = right[state]; // follow 1-bit (EOS is all 1s) + } + + return true; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/PendingWrite.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/PendingWrite.java new file mode 100644 index 0000000000..0579f25260 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/PendingWrite.java @@ -0,0 +1,46 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.nio.ByteBuffer; + +/** + * A pending DATA frame write queued for the writer thread. + * + *

Mutable to allow reuse. The buffer is in read mode (ready for writing to socket). + */ +final class PendingWrite { + ByteBuffer data; + int flags; + boolean borrowed; // true if data came from pool and should be returned + volatile PendingWrite next; + + /** + * Initialize with a pooled buffer. + */ + PendingWrite init(ByteBuffer data, int flags) { + this.data = data; + this.flags = flags; + this.borrowed = true; + return this; + } + + /** + * Initialize with a non-pooled buffer (caller manages lifecycle). + */ + PendingWrite initDirect(ByteBuffer data, int flags) { + this.data = data; + this.flags = flags; + this.borrowed = false; + return this; + } + + void reset() { + this.data = null; + this.flags = 0; + this.borrowed = false; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StaticTable.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StaticTable.java new file mode 100644 index 0000000000..743244282f --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StaticTable.java @@ -0,0 +1,210 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import software.amazon.smithy.java.http.api.HeaderName; + +/** + * HPACK static table from RFC 7541 Appendix A. + * + *

The static table consists of 61 predefined header field entries, where index 0 is unused. + * + *

This implementation uses length-based bucketing for fast lookups with zero per-lookup + * allocations. Entries are grouped by header name length, so lookups only scan candidates + * with matching name length (typically 1-3 entries per bucket). + * + *

Header names use constants from {@link HeaderName} to enable pointer comparisons. + */ +final class StaticTable { + + private StaticTable() {} + + /** + * Number of entries in the static table. + */ + static final int SIZE = 61; + + private static final String[] NAMES = new String[SIZE + 1]; + private static final String[] VALUES = new String[SIZE + 1]; + + private static void entry(int index, String name, String value) { + NAMES[index] = name; + VALUES[index] = value; + } + + static { + // RFC 7541 Appendix A - Static Table Definition + entry(1, HeaderName.PSEUDO_AUTHORITY.name(), ""); + entry(2, HeaderName.PSEUDO_METHOD.name(), "GET"); + entry(3, HeaderName.PSEUDO_METHOD.name(), "POST"); + entry(4, HeaderName.PSEUDO_PATH.name(), "/"); + entry(5, HeaderName.PSEUDO_PATH.name(), "/index.html"); + entry(6, HeaderName.PSEUDO_SCHEME.name(), "http"); + entry(7, HeaderName.PSEUDO_SCHEME.name(), "https"); + entry(8, HeaderName.PSEUDO_STATUS.name(), "200"); + entry(9, HeaderName.PSEUDO_STATUS.name(), "204"); + entry(10, HeaderName.PSEUDO_STATUS.name(), "206"); + entry(11, HeaderName.PSEUDO_STATUS.name(), "304"); + entry(12, HeaderName.PSEUDO_STATUS.name(), "400"); + entry(13, HeaderName.PSEUDO_STATUS.name(), "404"); + entry(14, HeaderName.PSEUDO_STATUS.name(), "500"); + entry(15, HeaderName.ACCEPT_CHARSET.name(), ""); + entry(16, HeaderName.ACCEPT_ENCODING.name(), "gzip, deflate"); + entry(17, HeaderName.ACCEPT_LANGUAGE.name(), ""); + entry(18, HeaderName.ACCEPT_RANGES.name(), ""); + entry(19, HeaderName.ACCEPT.name(), ""); + entry(20, HeaderName.ACCESS_CONTROL_ALLOW_ORIGIN.name(), ""); + entry(21, HeaderName.AGE.name(), ""); + entry(22, HeaderName.ALLOW.name(), ""); + entry(23, HeaderName.AUTHORIZATION.name(), ""); + entry(24, HeaderName.CACHE_CONTROL.name(), ""); + entry(25, HeaderName.CONTENT_DISPOSITION.name(), ""); + entry(26, HeaderName.CONTENT_ENCODING.name(), ""); + entry(27, HeaderName.CONTENT_LANGUAGE.name(), ""); + entry(28, HeaderName.CONTENT_LENGTH.name(), ""); + entry(29, HeaderName.CONTENT_LOCATION.name(), ""); + entry(30, HeaderName.CONTENT_RANGE.name(), ""); + entry(31, HeaderName.CONTENT_TYPE.name(), ""); + entry(32, HeaderName.COOKIE.name(), ""); + entry(33, HeaderName.DATE.name(), ""); + entry(34, HeaderName.ETAG.name(), ""); + entry(35, HeaderName.EXPECT.name(), ""); + entry(36, HeaderName.EXPIRES.name(), ""); + entry(37, HeaderName.FROM.name(), ""); + entry(38, HeaderName.HOST.name(), ""); + entry(39, HeaderName.IF_MATCH.name(), ""); + entry(40, HeaderName.IF_MODIFIED_SINCE.name(), ""); + entry(41, HeaderName.IF_NONE_MATCH.name(), ""); + entry(42, HeaderName.IF_RANGE.name(), ""); + entry(43, HeaderName.IF_UNMODIFIED_SINCE.name(), ""); + entry(44, HeaderName.LAST_MODIFIED.name(), ""); + entry(45, HeaderName.LINK.name(), ""); + entry(46, HeaderName.LOCATION.name(), ""); + entry(47, HeaderName.MAX_FORWARDS.name(), ""); + entry(48, HeaderName.PROXY_AUTHENTICATE.name(), ""); + entry(49, HeaderName.PROXY_AUTHORIZATION.name(), ""); + entry(50, HeaderName.RANGE.name(), ""); + entry(51, HeaderName.REFERER.name(), ""); + entry(52, HeaderName.REFRESH.name(), ""); + entry(53, HeaderName.RETRY_AFTER.name(), ""); + entry(54, HeaderName.SERVER.name(), ""); + entry(55, HeaderName.SET_COOKIE.name(), ""); + entry(56, HeaderName.STRICT_TRANSPORT_SECURITY.name(), ""); + entry(57, HeaderName.TRANSFER_ENCODING.name(), ""); + entry(58, HeaderName.USER_AGENT.name(), ""); + entry(59, HeaderName.VARY.name(), ""); + entry(60, HeaderName.VIA.name(), ""); + entry(61, HeaderName.WWW_AUTHENTICATE.name(), ""); + } + + /** + * Maximum header name length in the static table. + */ + private static final int MAX_NAME_LEN; + + /** + * Empty bucket for lengths with no entries (avoids null checks in lookups). + */ + private static final int[] EMPTY_BUCKET = new int[0]; + + /** + * Buckets of static table indices grouped by header name length. + * NAME_BUCKETS_BY_LEN[len] contains indices of entries whose name has that length. + */ + private static final int[][] NAME_BUCKETS_BY_LEN; + + static { + // Build length-based buckets for fast lookup + int maxLen = 0; + for (int i = 1; i <= SIZE; i++) { + int len = NAMES[i].length(); + if (len > maxLen) { + maxLen = len; + } + } + MAX_NAME_LEN = maxLen; + + // Count entries per length + int[] counts = new int[MAX_NAME_LEN + 1]; + for (int i = 1; i <= SIZE; i++) { + counts[NAMES[i].length()]++; + } + + // Allocate buckets + int[][] buckets = new int[MAX_NAME_LEN + 1][]; + for (int len = 0; len <= MAX_NAME_LEN; len++) { + buckets[len] = counts[len] > 0 ? new int[counts[len]] : EMPTY_BUCKET; + } + + // Fill buckets + int[] pos = new int[MAX_NAME_LEN + 1]; + for (int i = 1; i <= SIZE; i++) { + int len = NAMES[i].length(); + buckets[len][pos[len]++] = i; + } + + NAME_BUCKETS_BY_LEN = buckets; + } + + /** + * Get the header name at the given index. + * + * @param index 1-based index into static table + * @return header name + */ + static String getName(int index) { + return NAMES[index]; + } + + /** + * Get the header value at the given index. + * + * @param index 1-based index into static table + * @return header value + */ + static String getValue(int index) { + return VALUES[index]; + } + + /** + * Find index for a full match (name + value). + * + * @param name header name + * @param value header value + * @return index if found, -1 otherwise + */ + static int findFullMatch(String name, String value) { + int len = name.length(); + if (len > MAX_NAME_LEN) { + return -1; + } + for (int idx : NAME_BUCKETS_BY_LEN[len]) { + String entryName = NAMES[idx]; + if (name.equals(entryName) && value.equals(VALUES[idx])) { + return idx; + } + } + return -1; + } + + /** + * Find index for a name-only match. + * + * @param name header name + * @return index of first entry with this name, -1 if not found + */ + static int findNameMatch(String name) { + int len = name.length(); + if (len <= MAX_NAME_LEN) { + for (int idx : NAME_BUCKETS_BY_LEN[len]) { + if (name.equals(NAMES[idx])) { + return idx; + } + } + } + return -1; + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StreamRegistry.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StreamRegistry.java new file mode 100644 index 0000000000..537caef650 --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/h2/StreamRegistry.java @@ -0,0 +1,186 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.IntPredicate; + +/** + * Essentially a very fast custom hashmap of stream ID to H2Exchange. + * + *

Architecture: + *

    + *
  • L1 Cache (Array): A fast, direct-mapped AtomicReferenceArray. 99% of streams live here. + *
  • L2 Storage (Map): A ConcurrentHashMap spillover. If the array slot for a new stream is already + * occupied (by a long-lived stream), the new stream goes here.
  • + *
+ * + *

The spillover mechanism handles slot collisions: since we map stream IDs to slots via modulo, a long-lived + * stream occupying a slot would block newer streams that hash to the same slot. The spillover map ensures these + * newer streams are still tracked. Note that HTTP/2 stream IDs never wrap around on the same connection - they + * monotonically increase until exhaustion (at which point the connection must be closed per RFC 9113). + * + *

HTTP/2 client stream IDs have useful properties we exploit: + *

    + *
  • Always odd numbers: 1, 3, 5, 7, ...
  • + *
  • Monotonically increasing (never reused on same connection)
  • + *
+ * + *

We map stream IDs to array slots via: {@code slot = ((streamId - 1) >>> 1) & slotMask}. This converts + * odd IDs (1, 3, 5, ...) to sequential indices (0, 1, 2, ...) then masks to the slot range, giving O(1) lookup + * without hashing or Integer boxing overhead. + * + *

This class is a thread-safe registry and does not enforce any stream lifecycle policies + * (timeouts, errors, etc). Callers are responsible for managing timeouts and cleanup using forEach / clearAndClose. + */ +final class StreamRegistry { + + // 4096 slots covers normal concurrency (100-1000) with ample headroom. + // Memory cost: 4096 * 4-8 bytes (ref) = 16-32KB per connection (depends on compressed oops). + private static final int SLOTS = 4096; + private static final int SLOT_MASK = SLOTS - 1; + + private final AtomicReferenceArray fastPath = new AtomicReferenceArray<>(SLOTS); + private final ConcurrentHashMap spillover = new ConcurrentHashMap<>(); + + /** + * Map stream ID to slot index. + * Stream IDs are odd (1, 3, 5, ...), so we subtract 1 and divide by 2 to get sequential indices (0, 1, 2, ...). + */ + private static int streamIdToSlot(int streamId) { + return ((streamId - 1) >>> 1) & SLOT_MASK; + } + + /** + * Register a new exchange. + * + *

If the array slot is empty, the exchange goes there (fast path). If the slot is occupied by a long-lived + * stream, the new exchange spills over to the ConcurrentHashMap as a safety net. + * + * @param streamId the stream ID + * @param exchange the exchange to register + */ + void put(int streamId, H2Exchange exchange) { + int slot = streamIdToSlot(streamId); + + // Optimistic: Try to put in the fast array + H2Exchange existing = fastPath.get(slot); + + if (existing == null) { + // Slot is empty, claim it. + fastPath.set(slot, exchange); + } else { + // Collision: the slot is taken by an older, long-lived stream. Don't overwrite it, rather spill over. + spillover.put(streamId, exchange); + } + } + + /** + * Get an exchange by stream ID. + * + *

First checks the fast array path, then falls back to the spillover map if there's a stream ID mismatch + * (indicating the stream was spilled). + * + * @param streamId the stream ID + * @return the exchange, or null if not found + */ + H2Exchange get(int streamId) { + int slot = streamIdToSlot(streamId); + H2Exchange exchange = fastPath.get(slot); + return exchange != null && exchange.getStreamId() == streamId ? exchange : spillover.get(streamId); + } + + /** + * Remove an exchange from the registry. + * + * @param streamId the stream ID + * @return true if the exchange was removed, false if not found + */ + boolean remove(int streamId) { + int slot = streamIdToSlot(streamId); + H2Exchange exchange = fastPath.get(slot); + + // Check Fast Path + if (exchange != null && exchange.getStreamId() == streamId) { + // CAS ensures we don't delete a NEW stream that just claimed the slot + return fastPath.compareAndSet(slot, exchange, null); + } + + // Check Slow Path + return spillover.remove(streamId) != null; + } + + /** + * Iterate over all active exchanges with a context value. + * Avoids lambda allocation by passing context to a BiConsumer. + * + * @param action the action to perform on each exchange + * @param context context value passed to each invocation + * @param the context type + */ + void forEach(T context, BiConsumer action) { + for (int i = 0; i < SLOTS; i++) { + H2Exchange exchange = fastPath.get(i); + if (exchange != null) { + action.accept(exchange, context); + } + } + + if (!spillover.isEmpty()) { + for (H2Exchange exchange : spillover.values()) { + action.accept(exchange, context); + } + } + } + + /** + * Iterate over exchanges matching a predicate. + * + * @param predicate condition to check + * @param action the action to perform on matching exchanges + */ + void forEachMatching(IntPredicate predicate, Consumer action) { + // Iterate Array and spillover map. + for (int i = 0; i < SLOTS; i++) { + H2Exchange exchange = fastPath.get(i); + if (exchange != null && predicate.test(exchange.getStreamId())) { + action.accept(exchange); + } + } + + if (!spillover.isEmpty()) { + for (H2Exchange exchange : spillover.values()) { + if (predicate.test(exchange.getStreamId())) { + action.accept(exchange); + } + } + } + } + + /** + * Clear all slots and close exchanges. + * + * @param closeAction action to run on each exchange during clear + */ + void clearAndClose(Consumer closeAction) { + for (int i = 0; i < SLOTS; i++) { + H2Exchange exchange = fastPath.getAndSet(i, null); + if (exchange != null) { + closeAction.accept(exchange); + } + } + + if (!spillover.isEmpty()) { + for (H2Exchange exchange : spillover.values()) { + closeAction.accept(exchange); + } + spillover.clear(); + } + } +} diff --git a/http/http-client/src/main/java/software/amazon/smithy/java/http/client/package-info.java b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/package-info.java new file mode 100644 index 0000000000..a1894e97ab --- /dev/null +++ b/http/http-client/src/main/java/software/amazon/smithy/java/http/client/package-info.java @@ -0,0 +1,6 @@ +/** + * Virtual thread friendly Smithy HTTP client. + * + *

This package is unstable and subject to change. + */ +package software.amazon.smithy.java.http.client; diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/DefaultHttpClientTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/DefaultHttpClientTest.java new file mode 100644 index 0000000000..8b75f5f433 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/DefaultHttpClientTest.java @@ -0,0 +1,1048 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; +import javax.net.ssl.SSLSession; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.connection.ConnectionPool; +import software.amazon.smithy.java.http.client.connection.HttpConnection; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class DefaultHttpClientTest { + + @Test + void sendReturnsResponse() throws IOException { + var pool = new TestConnectionPool(); + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(200, response.statusCode(), "Should return status from exchange"); + assertEquals("test-body", + new String(response.body().asInputStream().readAllBytes()), + "Should return body from exchange"); + } + } + + @Test + void requestEndFiresWhenResponseBodyIsConsumed() throws IOException { + var starts = new AtomicInteger(); + var ends = new AtomicInteger(); + var startedExchangeId = new AtomicLong(); + var endedExchangeId = new AtomicLong(); + var listener = new HttpClientListener() { + @Override + public void onRequestStart(long exchangeId, HttpRequest request) { + starts.incrementAndGet(); + startedExchangeId.set(exchangeId); + } + + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + ends.incrementAndGet(); + endedExchangeId.set(exchangeId); + } + }; + + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> new TestConnectionPool()) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(1, starts.get()); + assertEquals(0, ends.get(), "Streaming request should not end when headers are returned"); + + assertEquals("test-body", new String(response.body().asInputStream().readAllBytes())); + + assertEquals(1, ends.get()); + assertEquals(startedExchangeId.get(), endedExchangeId.get()); + } + } + + @Test + void listenerExceptionDoesNotFailRequest() throws IOException { + var listener = new HttpClientListener() { + @Override + public void onRequestStart(long exchangeId, HttpRequest request) { + throw new RuntimeException("boom"); + } + + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + throw new RuntimeException("boom"); + } + }; + + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> new TestConnectionPool()) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(200, response.statusCode()); + response.body().discard(); + } + } + + @Test + void connectionPoolFactoryReceivesClientListeners() throws IOException { + var listener = new HttpClientListener() {}; + var sawListener = new AtomicBoolean(); + var pool = new TestConnectionPool(); + + try (var client = HttpClient.builder() + .addListener(listener) + .connectionPoolFactory(config -> { + sawListener.set(config.listeners().contains(listener)); + return pool; + }) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + client.send(request).body().discard(); + + assertTrue(sawListener.get(), "Custom pool factory must receive the client listener config"); + } + } + + @Test + void requestEndFiresOnExchangeCreationFailure() throws IOException { + var starts = new AtomicInteger(); + var ends = new AtomicInteger(); + var endedError = new AtomicReference(); + var startedExchangeId = new AtomicLong(); + var endedExchangeId = new AtomicLong(); + var listener = new HttpClientListener() { + @Override + public void onRequestStart(long exchangeId, HttpRequest request) { + starts.incrementAndGet(); + startedExchangeId.set(exchangeId); + } + + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + ends.incrementAndGet(); + endedExchangeId.set(exchangeId); + endedError.set(error); + } + }; + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + throw new IOException("exchange creation failed"); + } + }; + } + }; + + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + assertThrows(IOException.class, () -> client.send(request)); + + assertEquals(1, starts.get()); + assertEquals(1, ends.get()); + assertEquals(startedExchangeId.get(), endedExchangeId.get()); + assertEquals("exchange creation failed", endedError.get().getMessage()); + } + } + + @Test + void proxyFallbackKeepsSingleExchangeId() throws IOException { + var startedExchangeId = new AtomicLong(); + var endedExchangeId = new AtomicLong(); + var acquiredExchangeIds = new ArrayList(); + var listener = new HttpClientListener() { + @Override + public void onRequestStart(long exchangeId, HttpRequest request) { + startedExchangeId.set(exchangeId); + } + + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + endedExchangeId.set(exchangeId); + } + }; + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + acquiredExchangeIds.add(exchangeId); + if (route.proxy() != null && route.proxy().port() == 8080) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) + throws IOException { + throw new IOException("first proxy failed"); + } + }; + } + return super.acquire(route, exchangeId, options); + } + }; + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2.example.com:9090"), + ProxyConfiguration.ProxyType.HTTP); + + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxySelector(ProxySelector.of(proxy1, proxy2)) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + response.body().discard(); + + assertEquals(2, acquiredExchangeIds.size()); + assertEquals(startedExchangeId.get(), acquiredExchangeIds.get(0)); + assertEquals(startedExchangeId.get(), acquiredExchangeIds.get(1)); + assertEquals(startedExchangeId.get(), endedExchangeId.get()); + } + } + + @Test + void proxyFallbackDoesNotEndExchangeOnPerRouteFailure() throws IOException { + // Regression: the first proxy fails AFTER the exchange is created (mid response-read), then the + // second proxy succeeds. onRequestEnd must fire exactly once, with no error, when the successful + // response body is closed — not prematurely with the first proxy's failure. + var ends = new ArrayList(); + var listener = new HttpClientListener() { + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + ends.add(error); + } + }; + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + if (route.proxy() != null && route.proxy().port() == 8080) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) { + return new TestHttpExchange() { + @Override + public int responseStatusCode() throws IOException { + throw new IOException("first proxy failed mid-response"); + } + }; + } + }; + } + return super.acquire(route, exchangeId, options); + } + }; + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2.example.com:9090"), + ProxyConfiguration.ProxyType.HTTP); + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxySelector(ProxySelector.of(proxy1, proxy2)) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + assertTrue(ends.isEmpty(), "onRequestEnd must not fire while a later proxy may still succeed"); + + response.body().discard(); + + assertEquals(1, ends.size(), "onRequestEnd must fire exactly once"); + assertEquals(null, ends.get(0), "Successful request must end with no error"); + } + } + + @Test + void requestEndFiresOnceOnTimeout() throws IOException { + // Regression: a timeout is observed on the caller thread, not the worker VT. onRequestEnd must + // still fire exactly once with the timeout error. + var ends = new ArrayList(); + var listener = new HttpClientListener() { + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + synchronized (ends) { + ends.add(error); + } + } + }; + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public int responseStatusCode() throws IOException { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + throw new IOException("interrupted", e); + } + return 200; + } + }; + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .addListener(listener) + .requestTimeout(Duration.ofMillis(50)) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTrue(ex.getMessage().contains("exceeded request timeout"), ex.getMessage()); + + synchronized (ends) { + assertEquals(1, ends.size(), "onRequestEnd must fire exactly once on timeout"); + assertTrue(ends.get(0) instanceof IOException, "End error should be the timeout IOException"); + } + } + } + + @Test + void listenerErrorDoesNotLeakOrFailRequest() throws IOException { + // Regression: listener isolation must catch Throwable, not just RuntimeException. An Error thrown + // from a callback must not propagate to the caller or skip connection cleanup. + var released = new AtomicBoolean(false); + var listener = new HttpClientListener() { + @Override + public void onRequestStart(long exchangeId, HttpRequest request) { + throw new AssertionError("boom"); + } + }; + var pool = new TestConnectionPool() { + @Override + public void release(HttpConnection connection) { + released.set(true); + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + assertEquals(200, response.statusCode(), "Listener Error must not fail the request"); + response.body().discard(); + assertTrue(released.get(), "Connection must still be released despite the listener Error"); + } + } + + @Test + void proxyFallbackContinuesPastUnsupportedSocksProxy() throws IOException { + // Regression: an unsupported (SOCKS) proxy is a per-route failure surfaced as an IOException, so the + // proxy loop must run connectFailed and try the next proxy rather than aborting the whole send. + // The real HttpConnectionFactory throws IOException for SOCKS; this models that at the pool boundary. + var socksAttempted = new AtomicBoolean(false); + var httpAttempted = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + if (route.proxy() != null && route.proxy().type() == ProxyConfiguration.ProxyType.SOCKS5) { + socksAttempted.set(true); + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) + throws IOException { + throw new IOException("SOCKS proxies not yet supported: SOCKS5"); + } + }; + } + httpAttempted.set(true); + return super.acquire(route, exchangeId, options); + } + }; + var socks = new ProxyConfiguration(SmithyUri.of("http://socks.example.com:1080"), + ProxyConfiguration.ProxyType.SOCKS5); + var http = new ProxyConfiguration(SmithyUri.of("http://http.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + var connectFailedFor = new ArrayList(); + var selector = new ProxySelector() { + @Override + public List select(SmithyUri target) { + return List.of(socks, http); + } + + @Override + public void connectFailed(SmithyUri target, ProxyConfiguration proxy, IOException cause) { + connectFailedFor.add(proxy); + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxySelector(selector) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(200, response.statusCode(), "Should succeed via the HTTP proxy after SOCKS fails"); + assertTrue(socksAttempted.get(), "SOCKS proxy should have been attempted first"); + assertTrue(httpAttempted.get(), "HTTP proxy should be tried after the SOCKS attempt fails"); + assertEquals(List.of(socks), connectFailedFor, "connectFailed should fire for the SOCKS proxy"); + } + } + + @Test + void sendWritesRequestBody() throws IOException { + var bodyWritten = new AtomicReference(); + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public void writeRequestBody(DataStream body) throws IOException { + bodyWritten.set(body == null ? "" : new String(body.asInputStream().readAllBytes())); + } + }; + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("POST") + .setUri(SmithyUri.of("http://example.com/test")) + .setBody(DataStream.ofString("request-body")); + + client.send(request); + + assertEquals("request-body", bodyWritten.get(), "Request body should be written"); + } + } + + @Test + void requestTimeoutThrowsOnTimeout() throws IOException { + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public int responseStatusCode() throws IOException { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + throw new IOException("interrupted", e); + } + return 200; + } + }; + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .requestTimeout(Duration.ofMillis(50)) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertTrue(ex.getMessage().contains("exceeded request timeout"), + "Should indicate timeout: " + ex.getMessage()); + } + } + + @Test + void requestTimeoutSucceedsWhenFastEnough() throws IOException { + var pool = new TestConnectionPool(); + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .requestTimeout(Duration.ofSeconds(5)) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(200, response.statusCode(), "Should complete within timeout"); + } + } + + @Test + void proxySelectorsAreUsed() throws IOException { + var proxyUsed = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + if (route.usesProxy()) { + proxyUsed.set(true); + } + return super.acquire(route, exchangeId, options); + } + }; + var proxy = new ProxyConfiguration(SmithyUri.of("http://proxy.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxy(proxy) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + client.send(request); + + assertTrue(proxyUsed.get(), "Proxy should be used"); + } + } + + @Test + void proxyFailoverSucceedsOnSecondProxy() throws IOException { + var attemptedProxies = new AtomicInteger(0); + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + attemptedProxies.incrementAndGet(); + if (route.proxy() != null && route.proxy().port() == 8080) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) + throws IOException { + throw new IOException("first proxy failed"); + } + }; + } + return super.acquire(route, exchangeId, options); + } + }; + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2.example.com:9090"), + ProxyConfiguration.ProxyType.HTTP); + var connectFailedCalled = new AtomicBoolean(false); + var selector = new ProxySelector() { + @Override + public List select(SmithyUri target) { + return List.of(proxy1, proxy2); + } + + @Override + public void connectFailed(SmithyUri target, ProxyConfiguration proxy, IOException cause) { + connectFailedCalled.set(true); + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxySelector(selector) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + + assertEquals(200, response.statusCode(), "Should succeed via second proxy"); + assertEquals(2, attemptedProxies.get(), "Should have tried both proxies"); + assertTrue(connectFailedCalled.get(), "connectFailed should be called for first proxy"); + } + } + + @Test + void proxyFailoverThrowsWhenAllProxiesFail() throws IOException { + var attemptedProxies = new AtomicInteger(0); + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + attemptedProxies.incrementAndGet(); + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + throw new IOException("proxy " + attemptedProxies.get() + " failed"); + } + }; + } + }; + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1.example.com:8080"), + ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2.example.com:9090"), + ProxyConfiguration.ProxyType.HTTP); + var selector = ProxySelector.of(proxy1, proxy2); + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .proxySelector(selector) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var ex = assertThrows(IOException.class, () -> client.send(request)); + assertEquals("proxy 2 failed", ex.getMessage(), "Should throw last proxy's exception"); + assertEquals(2, attemptedProxies.get(), "Should have tried both proxies"); + } + } + + @Test + void connectionEvictedOnExchangeCreationFailure() throws IOException { + var evicted = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + throw new IOException("exchange creation failed"); + } + }; + } + + @Override + public void evict(HttpConnection connection, boolean close) { + evicted.set(true); + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + assertThrows(IOException.class, () -> client.send(request)); + assertTrue(evicted.get(), "Connection should be evicted on exchange creation failure"); + } + } + + @Test + void readNBytesExactKnownLengthReleasesConnection() throws IOException { + var released = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public HttpHeaders responseHeaders() { + return HttpHeaders.of(Map.of("content-length", List.of("9"))); + } + }; + } + + @Override + public void release(HttpConnection connection) { + released.set(true); + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + var stream = response.body().asInputStream(); + + assertEquals("test", new String(stream.readNBytes(4))); + assertFalse(released.get(), "Connection should remain leased until the known body length is consumed"); + + assertEquals("-body", new String(stream.readNBytes(5))); + assertTrue(released.get(), "Connection should release when readNBytes consumes the known body length"); + } + } + + @Test + void discardDrainsH2ResponseBeforeReleasingConnection() throws IOException { + var drained = new AtomicBoolean(false); + var closed = new AtomicBoolean(false); + var released = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public HttpVersion responseVersion() { + return HttpVersion.HTTP_2; + } + + @Override + public void discardResponseBody() { + drained.set(true); + } + + @Override + public void close() { + closed.set(true); + } + }; + } + + @Override + public void release(HttpConnection connection) { + released.set(true); + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + response.body().discard(); + + assertTrue(drained.get(), "H2 discard should drain the response body instead of immediately closing"); + assertTrue(closed.get(), "Exchange should still close after the body is drained"); + assertTrue(released.get(), "Drained H2 exchange should release the connection"); + } + } + + // Test fixtures + + private static class TestConnectionPool implements ConnectionPool { + @Override + public HttpConnection acquire(Route route, long exchangeId, RequestOptions options) { + return new TestConnection() { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) { + return createExchange(); + } + }; + } + + protected HttpExchange createExchange() { + return new TestHttpExchange(); + } + + @Override + public void release(HttpConnection connection) {} + + @Override + public void evict(HttpConnection connection, boolean close) {} + + @Override + public void close() {} + + @Override + public void shutdown(Duration timeout) {} + } + + private static class TestConnection implements HttpConnection { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) throws IOException { + return new TestHttpExchange(); + } + + @Override + public HttpVersion httpVersion() { + return HttpVersion.HTTP_1_1; + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public Route route() { + return Route.direct("http", "example.com", 80); + } + + @Override + public void close() {} + + @Override + public SSLSession sslSession() { + return null; + } + + @Override + public String negotiatedProtocol() { + return null; + } + + @Override + public boolean validateForReuse() { + return true; + } + } + + @Test + void closingOpenedChannelClosesChannelNotDiscard() throws IOException { + // Regression for drainOrDiscardBody: when the caller opened the body as a channel, teardown must + // close that channel, NOT call discardResponseBody (the "never opened" branch). Guards the + // wrappedChannel != null vs == null distinction. + var channelClosed = new AtomicBoolean(false); + var discardCalled = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public ReadableByteChannel responseBodyChannel() { + return new ReadableByteChannel() { + private final ReadableByteChannel inner = + Channels.newChannel(new ByteArrayInputStream("test-body".getBytes())); + + @Override + public int read(ByteBuffer dst) throws IOException { + return inner.read(dst); + } + + @Override + public boolean isOpen() { + return inner.isOpen(); + } + + @Override + public void close() throws IOException { + channelClosed.set(true); + inner.close(); + } + }; + } + + @Override + public void discardResponseBody() { + discardCalled.set(true); + } + }; + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + response.body().asChannel(); // opens the channel, sets wrappedChannel + response.body().close(); + + assertTrue(channelClosed.get(), "Opened channel must be closed on teardown"); + assertFalse(discardCalled.get(), "discardResponseBody must not run when a channel was opened"); + } + } + + @Test + void discardWithoutOpeningBodyDiscardsAtExchange() throws IOException { + // Regression for drainOrDiscardBody: when the body was never opened, teardown must discard at the + // exchange level (the final else branch), not touch a stream or channel. + var discardCalled = new AtomicBoolean(false); + var released = new AtomicBoolean(false); + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public void discardResponseBody() { + discardCalled.set(true); + } + }; + } + + @Override + public void release(HttpConnection connection) { + released.set(true); + } + }; + try (var client = HttpClient.builder().connectionPoolFactory(config -> pool).build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + response.body().discard(); // never opened the body + + assertTrue(discardCalled.get(), "Unopened body must be discarded at the exchange level"); + assertTrue(released.get(), "Connection must be released after a clean discard"); + } + } + + /** The body-consumption methods whose read failure must route through the error terminal. */ + static Stream failingBodyConsumers() { + return Stream.of( + Arguments.of("asInputStream.readAllBytes", + (BodyConsumer) body -> body.asInputStream().readAllBytes()), + Arguments.of("asInputStream.read", + (BodyConsumer) body -> body.asInputStream().read()), + Arguments.of("asChannel.read", + (BodyConsumer) body -> body.asChannel().read(ByteBuffer.allocate(16))), + Arguments.of("writeTo.outputStream", + (BodyConsumer) body -> body.writeTo(OutputStream.nullOutputStream())), + Arguments.of("writeTo.channel", + (BodyConsumer) body -> body.writeTo(Channels.newChannel(OutputStream.nullOutputStream())))); + } + + @FunctionalInterface + interface BodyConsumer { + void consume(DataStream body) throws IOException; + } + + @ParameterizedTest(name = "{0}") + @MethodSource("failingBodyConsumers") + void bodyReadFailureEndsWithErrorAndEvicts(String name, BodyConsumer consumer) throws IOException { + // Regression for the error-terminal routing across every consumption path (input stream, channel, + // and both writeTo variants): a body read that throws must fire onRequestEnd WITH the error and + // evict the torn connection — not report a clean close (onRequestEnd(null)) and pool it. + var endedError = new AtomicReference(); + var ends = new AtomicInteger(); + var evicted = new AtomicBoolean(false); + var released = new AtomicBoolean(false); + var boom = new IOException("read blew up"); + var listener = new HttpClientListener() { + @Override + public void onRequestEnd(long exchangeId, Throwable error) { + ends.incrementAndGet(); + endedError.set(error); + } + }; + var pool = new TestConnectionPool() { + @Override + protected HttpExchange createExchange() { + return new TestHttpExchange() { + @Override + public InputStream responseBody() { + return new InputStream() { + @Override + public int read() throws IOException { + throw boom; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw boom; + } + }; + } + + @Override + public ReadableByteChannel responseBodyChannel() { + return new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + throw boom; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() {} + }; + } + }; + } + + @Override + public void evict(HttpConnection connection, boolean isError) { + evicted.set(true); + } + + @Override + public void release(HttpConnection connection) { + released.set(true); + } + }; + try (var client = HttpClient.builder() + .connectionPoolFactory(config -> pool) + .addListener(listener) + .build()) { + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + + var response = client.send(request); + assertThrows(IOException.class, () -> consumer.consume(response.body())); + + assertEquals(1, ends.get(), name + ": onRequestEnd must fire exactly once"); + assertEquals(boom, endedError.get(), name + ": onRequestEnd must carry the read failure, not null"); + assertTrue(evicted.get(), name + ": a torn connection must be evicted"); + assertFalse(released.get(), name + ": a torn connection must NOT be released to the pool"); + } + } + + private static class TestHttpExchange implements HttpExchange { + @Override + public HttpRequest request() { + return HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("http://example.com/test")); + } + + @Override + public void writeRequestBody(DataStream body) throws IOException {} + + @Override + public InputStream responseBody() { + return new ByteArrayInputStream("test-body".getBytes()); + } + + @Override + public HttpHeaders responseHeaders() { + return HttpHeaders.of(Map.of()); + } + + @Override + public int responseStatusCode() throws IOException { + return 200; + } + + @Override + public HttpVersion responseVersion() { + return HttpVersion.HTTP_1_1; + } + + @Override + public void close() {} + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/HttpCredentialsTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/HttpCredentialsTest.java new file mode 100644 index 0000000000..aede795297 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/HttpCredentialsTest.java @@ -0,0 +1,89 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class HttpCredentialsTest { + + @Test + void basicAddsAuthHeader() { + var creds = new HttpCredentials.Basic("user", "pass"); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + boolean result = creds.authenticate(request, null); + + assertTrue(result); + + var built = request; + var authHeader = built.headers().firstValue("Authorization"); + var expected = "Basic " + Base64.getEncoder().encodeToString("user:pass".getBytes(StandardCharsets.UTF_8)); + assertEquals(expected, authHeader); + } + + @Test + void basicForProxyAddsProxyAuthHeader() { + var creds = new HttpCredentials.Basic("user", "pass", true); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + boolean result = creds.authenticate(request, null); + + assertTrue(result); + var built = request; + var authHeader = built.headers().firstValue("Proxy-Authorization"); + var expected = "Basic " + Base64.getEncoder().encodeToString("user:pass".getBytes(StandardCharsets.UTF_8)); + assertEquals(expected, authHeader); + } + + @Test + void basicReturnsFalseOnChallenge() { + var creds = new HttpCredentials.Basic("user", "pass"); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + var priorResponse = HttpResponse.create().setStatusCode(401); + boolean result = creds.authenticate(request, priorResponse); + + assertFalse(result); + } + + @Test + void bearerAddsAuthHeader() { + var creds = new HttpCredentials.Bearer("my-token"); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + boolean result = creds.authenticate(request, null); + + assertTrue(result); + var built = request; + assertEquals("Bearer my-token", built.headers().firstValue("Authorization")); + } + + @Test + void bearerForProxyAddsProxyAuthHeader() { + var creds = new HttpCredentials.Bearer("my-token", true); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + boolean result = creds.authenticate(request, null); + + assertTrue(result); + var built = request; + assertEquals("Bearer my-token", built.headers().firstValue("Proxy-Authorization")); + } + + @Test + void bearerReturnsFalseOnChallenge() { + var creds = new HttpCredentials.Bearer("my-token"); + var request = HttpRequest.create().setMethod("GET").setUri(SmithyUri.of("http://example.com")); + var priorResponse = HttpResponse.create().setStatusCode(401); + boolean result = creds.authenticate(request, priorResponse); + + assertFalse(result); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ManagedResponseInputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ManagedResponseInputStreamTest.java new file mode 100644 index 0000000000..85e297fe69 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ManagedResponseInputStreamTest.java @@ -0,0 +1,306 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Covers {@link ManagedResponseInputStream#readAllBytes()}, in particular the pre-sized + * known-Content-Length fast path and its fallbacks, plus the {@code onClose} lifecycle hook. + */ +class ManagedResponseInputStreamTest { + + private static byte[] bytes(int n) { + byte[] b = new byte[n]; + for (int i = 0; i < n; i++) { + b[i] = (byte) (i * 31 + 7); + } + return b; + } + + @Test + void readAllBytesKnownLengthExact() throws IOException { + byte[] payload = bytes(5000); + var closed = new AtomicInteger(); + var in = new ManagedResponseInputStream( + new ByteArrayInputStream(payload), + payload.length, + closed::incrementAndGet); + + assertArrayEquals(payload, in.readAllBytes()); + assertTrue(closed.get() >= 1, "onClose must run after readAllBytes"); + } + + @Test + void readAllBytesKnownLengthDripFed() throws IOException { + // Stream that returns at most 64 bytes per read — exercises the fill loop in readKnownLength. + byte[] payload = bytes(4096); + var in = new ManagedResponseInputStream( + new ChunkedStream(payload, 64), + payload.length, + () -> {}); + assertArrayEquals(payload, in.readAllBytes()); + } + + @Test + void readAllBytesStreamShorterThanContentLength() throws IOException { + // Header claims more than the stream delivers: must return exactly what was read. + byte[] payload = bytes(1000); + var in = new ManagedResponseInputStream( + new ByteArrayInputStream(payload), + 4096, // overstated length + () -> {}); + assertArrayEquals(payload, in.readAllBytes()); + } + + @Test + void readAllBytesReadsExactlyContentLength() throws IOException { + // In production the inner stream is a length-bounded FixedLengthResponseInputStream that + // returns EOF after exactly Content-Length bytes, so readAllBytes must read precisely that + // many — never peeking past, which on a pooled keep-alive connection would read into the + // next response. Model that bound: stop the stream at `len` even though more data follows. + byte[] full = bytes(3000); + int len = 1000; + var in = new ManagedResponseInputStream( + new BoundedStream(full, len), + len, + () -> {}); + byte[] expected = new byte[len]; + System.arraycopy(full, 0, expected, 0, len); + assertArrayEquals(expected, in.readAllBytes()); + } + + @Test + void readAllBytesUnknownLength() throws IOException { + byte[] payload = "hello world".getBytes(StandardCharsets.UTF_8); + var in = new ManagedResponseInputStream( + new ByteArrayInputStream(payload), + -1, // unknown + () -> {}); + assertArrayEquals(payload, in.readAllBytes()); + } + + @Test + void readAllBytesEmptyKnownLength() throws IOException { + var in = new ManagedResponseInputStream(new ByteArrayInputStream(new byte[0]), 0, () -> {}); + assertEquals(0, in.readAllBytes().length); + } + + // --- Error-terminal routing: a read that throws must run onError, never onClose. --- + + @Test + void readThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.read()); + } + + @Test + void readArrayThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.read(new byte[16])); + } + + @Test + void readAllBytesThrowsRunsOnErrorNotOnClose() throws IOException { + // The #3 regression: readAllBytes used finally{onClose} and reported a clean close on a torn read. + assertErrorTerminal(InputStream::readAllBytes); + } + + @Test + void transferToThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.transferTo(OutputStream.nullOutputStream())); + } + + @Test + void readNBytesThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.readNBytes(16)); + } + + @Test + void skipNBytesThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.skipNBytes(16)); + } + + @Test + void readNBytesArrayThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.readNBytes(new byte[16], 0, 16)); + } + + @Test + void skipThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(in -> in.skip(16)); + } + + @Test + void availableThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(InputStream::available); + } + + @Test + void resetThrowsRunsOnErrorNotOnClose() throws IOException { + assertErrorTerminal(InputStream::reset); + } + + @Test + void closeFailureRunsOnErrorNotOnClose() throws IOException { + // close() is a terminal too: a failing inner.close() must evict (onError), not report a clean close. + assertErrorTerminal(InputStream::close); + } + + /** + * Drive {@code op} against a stream whose operations throw, and assert the failure ran the error + * terminal (with the original exception) and NOT the success terminal. + */ + private static void assertErrorTerminal(ThrowingOp op) throws IOException { + var closed = new AtomicInteger(); + var errored = new AtomicReference(); + var boom = new IOException("boom"); + var in = new ManagedResponseInputStream( + new ThrowingStream(boom), + 1024, + closed::incrementAndGet, + errored::set); + + var thrown = Assertions.assertThrows(IOException.class, () -> op.run(in)); + + assertEquals(boom, thrown, "the original read exception must propagate"); + assertEquals(boom, errored.get(), "onError must run with the read failure"); + assertEquals(0, closed.get(), "onClose (success terminal) must NOT run on a failed read"); + } + + @FunctionalInterface + private interface ThrowingOp { + void run(ManagedResponseInputStream in) throws IOException; + } + + /** InputStream whose every read/skip/available throws the supplied exception. */ + private static final class ThrowingStream extends InputStream { + private final IOException error; + + ThrowingStream(IOException error) { + this.error = error; + } + + @Override + public int read() throws IOException { + throw error; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw error; + } + + @Override + public byte[] readAllBytes() throws IOException { + throw error; + } + + @Override + public byte[] readNBytes(int len) throws IOException { + throw error; + } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + throw error; + } + + @Override + public long skip(long n) throws IOException { + throw error; + } + + @Override + public void skipNBytes(long n) throws IOException { + throw error; + } + + @Override + public int available() throws IOException { + throw error; + } + + @Override + public void reset() throws IOException { + throw error; + } + + @Override + public void close() throws IOException { + throw error; + } + } + + /** + * InputStream that returns EOF after {@code limit} bytes even though {@code data} holds more — + * models the length-bounded FixedLengthResponseInputStream the production code wraps. + */ + private static final class BoundedStream extends InputStream { + private final byte[] data; + private final int limit; + private int pos; + + BoundedStream(byte[] data, int limit) { + this.data = data; + this.limit = limit; + } + + @Override + public int read() { + return pos < limit ? data[pos++] & 0xFF : -1; + } + + @Override + public int read(byte[] b, int off, int len) { + if (pos >= limit) { + return -1; + } + int n = Math.min(len, limit - pos); + System.arraycopy(data, pos, b, off, n); + pos += n; + return n; + } + } + + /** InputStream that serves at most {@code maxChunk} bytes per read call. */ + private static final class ChunkedStream extends InputStream { + private final byte[] data; + private final int maxChunk; + private int pos; + + ChunkedStream(byte[] data, int maxChunk) { + this.data = data; + this.maxChunk = maxChunk; + } + + @Override + public int read() { + return pos < data.length ? data[pos++] & 0xFF : -1; + } + + @Override + public int read(byte[] b, int off, int len) { + if (pos >= data.length) { + return -1; + } + int n = Math.min(Math.min(len, maxChunk), data.length - pos); + System.arraycopy(data, pos, b, off, n); + pos += n; + return n; + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ProxySelectorTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ProxySelectorTest.java new file mode 100644 index 0000000000..765f05c5b9 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/ProxySelectorTest.java @@ -0,0 +1,89 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class ProxySelectorTest { + + private static final SmithyUri TARGET = SmithyUri.of("https://example.com"); + + @Test + void directReturnsEmptyList() { + var selector = ProxySelector.direct(); + var result = selector.select(TARGET); + + assertTrue(result.isEmpty()); + } + + @Test + void ofReturnsSingleProxy() { + var proxy = new ProxyConfiguration(SmithyUri.of("http://proxy:8080"), ProxyConfiguration.ProxyType.HTTP); + var selector = ProxySelector.of(proxy); + var result = selector.select(TARGET); + + assertEquals(List.of(proxy), result); + } + + @Test + void ofReturnsMultipleProxiesInOrder() { + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1:8080"), ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2:8080"), ProxyConfiguration.ProxyType.HTTP); + var selector = ProxySelector.of(proxy1, proxy2); + var result = selector.select(TARGET); + + assertEquals(List.of(proxy1, proxy2), result); + } + + @Test + void noFailoverReturnsOnlyFirstProxy() { + var proxy1 = new ProxyConfiguration(SmithyUri.of("http://proxy1:8080"), ProxyConfiguration.ProxyType.HTTP); + var proxy2 = new ProxyConfiguration(SmithyUri.of("http://proxy2:8080"), ProxyConfiguration.ProxyType.HTTP); + var delegate = ProxySelector.of(proxy1, proxy2); + var selector = ProxySelector.noFailover(delegate); + var result = selector.select(TARGET); + + assertEquals(List.of(proxy1), result); + } + + @Test + void noFailoverReturnsEmptyWhenDelegateReturnsEmpty() { + var delegate = ProxySelector.direct(); + var selector = ProxySelector.noFailover(delegate); + var result = selector.select(TARGET); + + assertTrue(result.isEmpty()); + } + + @Test + void noFailoverDelegatesConnectFailed() { + var failedProxy = new AtomicReference(); + var proxy = new ProxyConfiguration(SmithyUri.of("http://proxy:8080"), ProxyConfiguration.ProxyType.HTTP); + var delegate = new ProxySelector() { + @Override + public List select(SmithyUri target) { + return List.of(proxy); + } + + @Override + public void connectFailed(SmithyUri target, ProxyConfiguration p, IOException cause) { + failedProxy.set(p); + } + }; + + var selector = ProxySelector.noFailover(delegate); + selector.connectFailed(TARGET, proxy, new IOException("test")); + + assertEquals(proxy, failedProxy.get()); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/RequestOptionsTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/RequestOptionsTest.java new file mode 100644 index 0000000000..fe57975737 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/RequestOptionsTest.java @@ -0,0 +1,179 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HeaderName; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class RequestOptionsTest { + + @Test + void defaultsAreAllNull() { + var options = RequestOptions.defaults(); + + assertNull(options.requestTimeout()); + assertNull(options.connectTimeout()); + assertNull(options.readTimeout()); + assertNull(options.acquireTimeout()); + assertNull(options.expectContinue()); + } + + @Test + void defaultsIsSingleton() { + assertSame(RequestOptions.defaults(), RequestOptions.defaults()); + } + + @Test + void builderSetsEveryField() { + var options = RequestOptions.builder() + .requestTimeout(Duration.ofSeconds(1)) + .connectTimeout(Duration.ofSeconds(2)) + .readTimeout(Duration.ofSeconds(3)) + .acquireTimeout(Duration.ofSeconds(4)) + .expectContinue(true) + .build(); + + assertEquals(Duration.ofSeconds(1), options.requestTimeout()); + assertEquals(Duration.ofSeconds(2), options.connectTimeout()); + assertEquals(Duration.ofSeconds(3), options.readTimeout()); + assertEquals(Duration.ofSeconds(4), options.acquireTimeout()); + assertEquals(Boolean.TRUE, options.expectContinue()); + } + + @Test + void equalsAndHashCodeAreValueBased() { + var a = RequestOptions.builder() + .requestTimeout(Duration.ofSeconds(1)) + .connectTimeout(Duration.ofSeconds(2)) + .readTimeout(Duration.ofSeconds(3)) + .acquireTimeout(Duration.ofSeconds(4)) + .expectContinue(true) + .build(); + var b = RequestOptions.builder() + .requestTimeout(Duration.ofSeconds(1)) + .connectTimeout(Duration.ofSeconds(2)) + .readTimeout(Duration.ofSeconds(3)) + .acquireTimeout(Duration.ofSeconds(4)) + .expectContinue(true) + .build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(RequestOptions.defaults(), RequestOptions.builder().build()); + assertEquals(RequestOptions.defaults().hashCode(), RequestOptions.builder().build().hashCode()); + } + + @Test + void notEqualWhenAnyFieldDiffers() { + var base = RequestOptions.builder().connectTimeout(Duration.ofSeconds(2)).build(); + + assertNotEquals(base, RequestOptions.builder().connectTimeout(Duration.ofSeconds(5)).build()); + assertNotEquals(base, RequestOptions.builder().readTimeout(Duration.ofSeconds(2)).build()); + assertNotEquals(base, RequestOptions.defaults()); + assertNotEquals(base, null); + } + + @Test + void rejectsNonPositiveTimeouts() { + assertThrows(IllegalArgumentException.class, + () -> RequestOptions.builder().requestTimeout(Duration.ZERO)); + assertThrows(IllegalArgumentException.class, + () -> RequestOptions.builder().connectTimeout(Duration.ofMillis(-1))); + assertThrows(IllegalArgumentException.class, + () -> RequestOptions.builder().readTimeout(Duration.ZERO)); + assertThrows(IllegalArgumentException.class, + () -> RequestOptions.builder().acquireTimeout(Duration.ofSeconds(-5))); + } + + @Test + void nullTimeoutsAreAccepted() { + var options = RequestOptions.builder() + .requestTimeout(null) + .connectTimeout(null) + .readTimeout(null) + .acquireTimeout(null) + .build(); + + assertNull(options.requestTimeout()); + assertNull(options.connectTimeout()); + assertNull(options.readTimeout()); + assertNull(options.acquireTimeout()); + } + + @Test + void applyExpectContinueNullLeavesRequestUntouched() { + var withHeader = request().toModifiableCopy().setHeader(HeaderName.EXPECT, "100-continue"); + var options = RequestOptions.defaults(); + + assertSame(withHeader, options.applyExpectContinue(withHeader)); + } + + @Test + void applyExpectContinueTrueAddsHeaderWhenAbsent() { + var request = request(); + var options = RequestOptions.builder().expectContinue(true).build(); + + var result = options.applyExpectContinue(request); + + assertEquals("100-continue", result.headers().firstValue(HeaderName.EXPECT)); + // Input is modifiable, so it is adjusted in place rather than copied. + assertSame(request, result); + } + + @Test + void applyExpectContinueTrueIsNoOpWhenAlreadyPresent() { + var request = request().toModifiableCopy().setHeader(HeaderName.EXPECT, "100-continue"); + var options = RequestOptions.builder().expectContinue(true).build(); + + assertSame(request, options.applyExpectContinue(request)); + } + + @Test + void applyExpectContinueFalseStripsHeader() { + var request = request().toModifiableCopy().setHeader(HeaderName.EXPECT, "100-continue"); + var options = RequestOptions.builder().expectContinue(false).build(); + + var result = options.applyExpectContinue(request); + + assertNull(result.headers().firstValue(HeaderName.EXPECT)); + // Input is modifiable, so it is adjusted in place rather than copied. + assertSame(request, result); + } + + @Test + void applyExpectContinueFalseIsNoOpWhenAbsent() { + var request = request(); + var options = RequestOptions.builder().expectContinue(false).build(); + + assertSame(request, options.applyExpectContinue(request)); + } + + @Test + void applyExpectContinueTreatsHeaderCaseInsensitively() { + var request = request().toModifiableCopy().setHeader(HeaderName.EXPECT, "100-Continue"); + var options = RequestOptions.builder().expectContinue(false).build(); + + var result = options.applyExpectContinue(request); + + assertTrue(result.headers().allValues(HeaderName.EXPECT).isEmpty()); + } + + private static HttpRequest request() { + return HttpRequest.create() + .setMethod("POST") + .setUri(SmithyUri.of("https://example.com/test")); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/AvailableTestTlsProvider.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/AvailableTestTlsProvider.java new file mode 100644 index 0000000000..946ae4ee94 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/AvailableTestTlsProvider.java @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; + +/** A discoverable, available {@link TlsProvider} used to test ServiceLoader-based selection. */ +public final class AvailableTestTlsProvider implements TlsProvider { + @Override + public ConnectionTransport connect(TlsConnectionContext connection) throws IOException { + throw new IOException("test provider does not connect"); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManagerTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManagerTest.java new file mode 100644 index 0000000000..0b9b9fbf06 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H1ConnectionManagerTest.java @@ -0,0 +1,390 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.SSLSession; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.HttpExchange; +import software.amazon.smithy.java.http.client.RequestOptions; + +class H1ConnectionManagerTest { + + private static final Route TEST_ROUTE = Route.direct("http", "example.com", 80); + private static final long MAX_IDLE_NANOS = TimeUnit.SECONDS.toNanos(30); + + @Test + void tryAcquireReturnsNullWhenPoolEmpty() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNull(result, "Should return null when pool is empty"); + } + + @Test + void tryAcquireReturnsPooledConnection() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var connection = new TestConnection(); + + manager.release(TEST_ROUTE, connection, false); + // Need to ensure pool exists first + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNotNull(result, "Should return pooled connection"); + assertEquals(connection, result, "Should return the same connection"); + } + + @Test + void tryAcquireRejectsOverlyIdleConnections() throws Exception { + var manager = new H1ConnectionManager(TimeUnit.MILLISECONDS.toNanos(10)); // 10ms max idle + var closeCalled = new AtomicBoolean(false); + var connection = new TestConnection() { + @Override + public void close() { + closeCalled.set(true); + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + + Thread.sleep(50); // Wait longer than max idle time + + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNull(result, "Should not return overly idle connection"); + assertTrue(closeCalled.get(), "Overly idle connection should be closed"); + } + + @Test + void tryAcquireValidatesConnectionIdleLongerThanThreshold() throws Exception { + var manager = new H1ConnectionManager(TimeUnit.SECONDS.toNanos(30)); // 30s max idle + var validateCalled = new AtomicBoolean(false); + var connection = new TestConnection() { + @Override + public boolean validateForReuse() { + validateCalled.set(true); + return true; + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + + Thread.sleep(1100); // Wait > 1 second (VALIDATION_THRESHOLD_NANOS) + + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNotNull(result, "Should return validated connection"); + assertTrue(validateCalled.get(), "validateForReuse should be called for connections idle > 1s"); + } + + @Test + void tryAcquireSkipsInvalidConnections() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var invalidConnection = new TestConnection() { + @Override + public boolean isActive() { + return false; + } + }; + var validConnection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, validConnection, false); + manager.release(TEST_ROUTE, invalidConnection, false); + + // Should skip invalid and return valid (LIFO order, so invalid is tried first) + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNotNull(result, "Should return valid connection"); + assertEquals(validConnection, result, "Should skip invalid and return valid"); + } + + @Test + void tryAcquireClosesInvalidConnections() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var closeCalled = new AtomicBoolean(false); + var active = new AtomicBoolean(true); + var invalidConnection = new TestConnection() { + @Override + public boolean isActive() { + return active.get(); + } + + @Override + public void close() { + closeCalled.set(true); + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, invalidConnection, false); + // Connection becomes inactive after being pooled + active.set(false); + + manager.tryAcquire(TEST_ROUTE, 10); + + assertTrue(closeCalled.get(), "Invalid connection should be closed"); + } + + @Test + void releaseReturnsFalseWhenConnectionInactive() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var inactiveConnection = new TestConnection() { + @Override + public boolean isActive() { + return false; + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + boolean released = manager.release(TEST_ROUTE, inactiveConnection, false); + + assertFalse(released, "Should not release inactive connection"); + } + + @Test + void releaseReturnsFalseWhenPoolClosed() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var connection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 10); + boolean released = manager.release(TEST_ROUTE, connection, true); + + assertFalse(released, "Should not release when pool is closed"); + } + + @Test + void releaseReturnsFalseWhenNoPoolExists() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var connection = new TestConnection(); + + boolean released = manager.release(TEST_ROUTE, connection, false); + + assertFalse(released, "Should not release when no pool exists"); + } + + @Test + void removeRemovesConnectionFromPool() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var connection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + manager.remove(TEST_ROUTE, connection); + + var result = manager.tryAcquire(TEST_ROUTE, 10); + + assertNull(result, "Connection should be removed from pool"); + } + + @Test + void cleanupIdleRemovesExpiredConnections() throws Exception { + var manager = new H1ConnectionManager(1); // 1 nanosecond max idle + var connection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + + Thread.sleep(10); // Ensure connection is expired + + var removed = new AtomicInteger(0); + int count = manager.cleanupIdle((conn, reason) -> removed.incrementAndGet()); + + assertEquals(1, count, "Should remove 1 expired connection"); + assertEquals(1, removed.get(), "Callback should be called once"); + } + + @Test + void cleanupIdleRemovesUnhealthyConnections() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var unhealthyConnection = new TestConnection() { + private boolean active = true; + + @Override + public boolean isActive() { + return active; + } + + void setInactive() { + active = false; + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, unhealthyConnection, false); + unhealthyConnection.setInactive(); + + var reasons = new ArrayList(); + manager.cleanupIdle((conn, reason) -> reasons.add(reason)); + + assertEquals(1, reasons.size(), "Should remove unhealthy connection"); + assertEquals(CloseReason.UNEXPECTED_CLOSE, reasons.get(0), "Reason should be UNEXPECTED_CLOSE"); + } + + @Test + void closeAllClosesAllConnections() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var closedConnections = new AtomicInteger(0); + var connection1 = new TestConnection() { + @Override + public void close() { + closedConnections.incrementAndGet(); + } + }; + var connection2 = new TestConnection() { + @Override + public void close() { + closedConnections.incrementAndGet(); + } + }; + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection1, false); + manager.release(TEST_ROUTE, connection2, false); + + var exceptions = new ArrayList(); + manager.closeAll(exceptions, conn -> {}); + + assertEquals(2, closedConnections.get(), "All connections should be closed"); + assertTrue(exceptions.isEmpty(), "No exceptions expected"); + } + + @Test + void getOrCreatePoolThrowsOnInconsistentMaxConnections() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + + manager.getOrCreatePool(TEST_ROUTE, 10); + + var ex = Assertions.assertThrows( + IllegalStateException.class, + () -> manager.getOrCreatePool(TEST_ROUTE, 20)); + + assertTrue(ex.getMessage().contains("maxConnections=10")); + assertTrue(ex.getMessage().contains("cannot change to 20")); + } + + @Test + void largeMaxConnectionsDoesNotPreallocateIdleStorage() { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + var connection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 1_000_000); + assertTrue(manager.release(TEST_ROUTE, connection, false)); + + assertEquals(connection, manager.tryAcquire(TEST_ROUTE, 1_000_000)); + } + + @Test + void acquireActiveHonorsMaxConnectionsPerRoute() throws Exception { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + + manager.acquireActive(TEST_ROUTE, 1, 1); + + var ex = Assertions.assertThrows( + IOException.class, + () -> manager.acquireActive(TEST_ROUTE, 1, 1)); + + assertTrue(ex.getMessage().contains("1 connections in use")); + + manager.releaseActive(TEST_ROUTE); + manager.acquireActive(TEST_ROUTE, 1, 1); + manager.releaseActive(TEST_ROUTE); + } + + @Test + void cleanupIdleRemovesEmptyPools() { + var manager = new H1ConnectionManager(1); // 1 nanosecond max idle + var connection = new TestConnection(); + + manager.getOrCreatePool(TEST_ROUTE, 10); + manager.release(TEST_ROUTE, connection, false); + + // First cleanup removes the expired connection + manager.cleanupIdle((conn, reason) -> {}); + + // Pool should be removed since it's empty + // Verify by checking that we can create a new pool with different maxConnections + // (would throw if old pool still existed) + manager.getOrCreatePool(TEST_ROUTE, 5); // Different maxConnections - should work + } + + @Test + void cleanupIdleDoesNotRemovePoolWithActiveConnections() throws Exception { + var manager = new H1ConnectionManager(MAX_IDLE_NANOS); + + manager.acquireActive(TEST_ROUTE, 1, 1); + + manager.cleanupIdle((conn, reason) -> {}); + + var ex = Assertions.assertThrows( + IOException.class, + () -> manager.acquireActive(TEST_ROUTE, 1, 1)); + + assertTrue(ex.getMessage().contains("1 connections in use")); + + manager.releaseActive(TEST_ROUTE); + } + + // Test connection implementation + private static class TestConnection implements HttpConnection { + @Override + public HttpExchange newExchange(HttpRequest request, RequestOptions options) { + return null; + } + + @Override + public HttpVersion httpVersion() { + return HttpVersion.HTTP_1_1; + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public Route route() { + return TEST_ROUTE; + } + + @Override + public void close() {} + + @Override + public SSLSession sslSession() { + return null; + } + + @Override + public String negotiatedProtocol() { + return null; + } + + @Override + public boolean validateForReuse() { + return true; + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancerTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancerTest.java new file mode 100644 index 0000000000..520de097af --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/H2LoadBalancerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class H2LoadBalancerTest { + + @Test + void rejectsSoftLimitAboveHardLimit() { + assertThrows(IllegalArgumentException.class, () -> H2LoadBalancer.watermark(11, 10)); + } + + @Test + void roundRobinsAcrossConnectionsBelowSoftLimit() { + H2LoadBalancer balancer = H2LoadBalancer.watermark(5, 10); + int[] activeStreams = {0, 0, 0}; + + assertEquals(0, balancer.select(activeStreams, 3, 3)); + assertEquals(1, balancer.select(activeStreams, 3, 3)); + assertEquals(2, balancer.select(activeStreams, 3, 3)); + assertEquals(0, balancer.select(activeStreams, 3, 3)); + } + + @Test + void createsNewConnectionWhenAllConnectionsReachSoftLimitAndCapacityRemains() { + H2LoadBalancer balancer = H2LoadBalancer.watermark(5, 10); + int[] activeStreams = {5, 6}; + + assertEquals(H2LoadBalancer.CREATE_NEW, balancer.select(activeStreams, 2, 3)); + } + + @Test + void selectsLeastLoadedConnectionBelowHardLimitWhenPoolCannotExpand() { + H2LoadBalancer balancer = H2LoadBalancer.watermark(5, 10); + int[] activeStreams = {9, 5, 7}; + + assertEquals(1, balancer.select(activeStreams, 3, 3)); + } + + @Test + void returnsSaturatedWhenNoConnectionCanAcceptStreams() { + H2LoadBalancer balancer = H2LoadBalancer.watermark(5, 10); + int[] activeStreams = {10, -1}; + + assertEquals(H2LoadBalancer.SATURATED, balancer.select(activeStreams, 2, 2)); + } + + @Test + void skipsConnectionsThatAreNotAcceptingStreams() { + H2LoadBalancer balancer = H2LoadBalancer.watermark(5, 10); + int[] activeStreams = {-1, 3}; + + assertEquals(1, balancer.select(activeStreams, 2, 2)); + assertTrue(balancer.select(activeStreams, 2, 2) >= 0); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactoryTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactoryTest.java new file mode 100644 index 0000000000..2e0d671799 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionFactoryTest.java @@ -0,0 +1,80 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class HttpConnectionFactoryTest { + + @Test + void acceptsNegotiatedH2WhenPolicyAllowsIt() throws IOException { + assertEquals(HttpConnectionFactory.Protocol.H2, + HttpConnectionFactory.selectProtocol("h2", true, HttpVersionPolicy.AUTOMATIC)); + assertEquals(HttpConnectionFactory.Protocol.H2, + HttpConnectionFactory.selectProtocol("h2", true, HttpVersionPolicy.ENFORCE_HTTP_2)); + } + + @Test + void rejectsNegotiatedH2WhenH1IsEnforced() { + assertThrows( + IOException.class, + () -> HttpConnectionFactory.selectProtocol("h2", true, HttpVersionPolicy.ENFORCE_HTTP_1_1)); + } + + @Test + void acceptsNegotiatedH1WhenPolicyAllowsIt() throws IOException { + assertEquals(HttpConnectionFactory.Protocol.H1, + HttpConnectionFactory.selectProtocol("http/1.1", true, HttpVersionPolicy.AUTOMATIC)); + assertEquals(HttpConnectionFactory.Protocol.H1, + HttpConnectionFactory.selectProtocol("http/1.1", true, HttpVersionPolicy.ENFORCE_HTTP_1_1)); + } + + @Test + void rejectsNegotiatedH1WhenH2IsEnforced() { + assertThrows( + IOException.class, + () -> HttpConnectionFactory.selectProtocol("http/1.1", true, HttpVersionPolicy.ENFORCE_HTTP_2)); + } + + @Test + void rejectsUnsupportedNegotiatedProtocol() { + assertThrows( + IOException.class, + () -> HttpConnectionFactory.selectProtocol("spdy/3", true, HttpVersionPolicy.AUTOMATIC)); + } + + @Test + void fallsBackToH1ForSecureAutomaticWhenNoAlpnWasNegotiated() throws IOException { + assertEquals(HttpConnectionFactory.Protocol.H1, + HttpConnectionFactory.selectProtocol(null, true, HttpVersionPolicy.AUTOMATIC)); + assertEquals(HttpConnectionFactory.Protocol.H1, + HttpConnectionFactory.selectProtocol("", true, HttpVersionPolicy.AUTOMATIC)); + } + + @Test + void rejectsSecureEnforcedH2WhenNoAlpnWasNegotiated() { + assertThrows( + IOException.class, + () -> HttpConnectionFactory.selectProtocol(null, true, HttpVersionPolicy.ENFORCE_HTTP_2)); + } + + @Test + void selectsH2cForCleartextPriorKnowledge() throws IOException { + assertEquals(HttpConnectionFactory.Protocol.H2, + HttpConnectionFactory.selectProtocol(null, false, HttpVersionPolicy.H2C_PRIOR_KNOWLEDGE)); + } + + @Test + void rejectsCleartextEnforcedH2WithoutH2cPriorKnowledge() { + assertThrows( + IOException.class, + () -> HttpConnectionFactory.selectProtocol(null, false, HttpVersionPolicy.ENFORCE_HTTP_2)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPoolTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPoolTest.java new file mode 100644 index 0000000000..433e9f7e09 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/HttpConnectionPoolTest.java @@ -0,0 +1,213 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.client.HttpClientListener; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.dns.DnsResolver; + +class HttpConnectionPoolTest { + + @Test + void h1IdleConnectionsCountTowardMaxTotalConnections() throws IOException { + var socketCreates = new AtomicInteger(); + var dns = DnsResolver.staticMapping(Map.of( + "one.example.com", + List.of(InetAddress.getByName("127.0.0.1")), + "two.example.com", + List.of(InetAddress.getByName("127.0.0.1")))); + try (var pool = new HttpConnectionPool(ConnectionConfig.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(1) + .maxConnectionsPerRoute(1) + .acquireTimeout(Duration.ZERO) + .dnsResolver(dns) + .socketFactory((route, endpoints) -> { + socketCreates.incrementAndGet(); + return new FakeSocket(); + }) + .build())) { + + var first = pool.acquire(Route.direct("http", "one.example.com", 80), 1, RequestOptions.defaults()); + pool.release(first); + + var ex = assertThrows( + IOException.class, + () -> pool.acquire(Route.direct("http", "two.example.com", 80), 2, RequestOptions.defaults())); + assertEquals("Connection pool exhausted: 1 connections in use (timed out after 0ms)", ex.getMessage()); + assertEquals(1, socketCreates.get(), "The idle first-route socket should still hold the global permit"); + } + } + + @Test + void perRequestAcquireTimeoutOverridesPoolDefault() throws IOException { + var dns = DnsResolver.staticMapping(Map.of( + "one.example.com", + List.of(InetAddress.getByName("127.0.0.1")), + "two.example.com", + List.of(InetAddress.getByName("127.0.0.1")))); + // Pool default acquire timeout is effectively unbounded; if the per-request override were ignored + // the second acquire would block ~forever instead of failing fast. + try (var pool = new HttpConnectionPool(ConnectionConfig.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(1) + .maxConnectionsPerRoute(1) + .acquireTimeout(Duration.ofHours(1)) + .dnsResolver(dns) + .socketFactory((route, endpoints) -> new FakeSocket()) + .build())) { + + var first = pool.acquire(Route.direct("http", "one.example.com", 80), 1, RequestOptions.defaults()); + pool.release(first); + + var shortTimeout = RequestOptions.builder().acquireTimeout(Duration.ofMillis(1)).build(); + var ex = assertThrows( + IOException.class, + () -> pool.acquire(Route.direct("http", "two.example.com", 80), 2, shortTimeout)); + assertTrue(ex.getMessage().contains("timed out after 1ms"), + "Expected per-request 1ms override in message, got: " + ex.getMessage()); + } + } + + @Test + void listenerReceivesExchangeScopedDnsAndConnectEvents() throws IOException { + var address = InetAddress.getByName("127.0.0.1"); + var events = new ArrayList(); + var dns = DnsResolver.staticMapping(Map.of("example.com", List.of(address))); + var listener = new HttpClientListener() { + @Override + public void onDnsStart(long exchangeId, String host) { + events.add("dns-start:" + exchangeId + ":" + host); + } + + @Override + public void onDnsEnd(long exchangeId, String host, List addresses, Throwable error) { + events.add("dns-end:" + exchangeId + ":" + host + ":" + addresses.size() + ":" + (error == null)); + } + + @Override + public void onConnectStart(long exchangeId, Route route, InetAddress address) { + events.add("connect-start:" + exchangeId + ":" + address.getHostAddress()); + } + + @Override + public void onConnectEnd(long exchangeId, Route route, InetAddress address, Throwable error) { + events.add("connect-end:" + exchangeId + ":" + address.getHostAddress() + ":" + (error == null)); + } + + @Override + public void onConnectionCreated(HttpConnection connection) { + events.add("created"); + } + + @Override + public void onConnectionAcquired(HttpConnection connection, boolean reused) { + events.add("acquired:" + reused); + } + }; + + try (var pool = new HttpConnectionPool(ConnectionConfig.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .dnsResolver(dns) + .socketFactory((route, endpoints) -> new FakeSocket()) + .addListener(listener) + .build())) { + pool.acquire(Route.direct("http", "example.com", 80), 123, RequestOptions.defaults()); + } + + assertEquals(List.of( + "dns-start:123:example.com", + "dns-end:123:example.com:1:true", + "connect-start:123:127.0.0.1", + "connect-end:123:127.0.0.1:true", + "created", + "acquired:false"), events); + } + + @Test + void listenerExceptionOnCloseDoesNotLeakPermit() throws IOException { + var dns = DnsResolver.staticMapping(Map.of( + "one.example.com", + List.of(InetAddress.getByName("127.0.0.1")), + "two.example.com", + List.of(InetAddress.getByName("127.0.0.1")))); + var listener = new HttpClientListener() { + @Override + public void onConnectionClosed(HttpConnection connection, CloseReason reason) { + throw new RuntimeException("boom"); + } + }; + + try (var pool = new HttpConnectionPool(ConnectionConfig.builder() + .httpVersionPolicy(HttpVersionPolicy.ENFORCE_HTTP_1_1) + .maxTotalConnections(1) + .maxConnectionsPerRoute(1) + .acquireTimeout(Duration.ZERO) + .dnsResolver(dns) + .socketFactory((route, endpoints) -> new FakeSocket()) + .addListener(listener) + .build())) { + var first = pool.acquire(Route.direct("http", "one.example.com", 80), 1, RequestOptions.defaults()); + pool.evict(first, false); + + var second = pool.acquire(Route.direct("http", "two.example.com", 80), 2, RequestOptions.defaults()); + assertEquals("two.example.com", second.route().host()); + } + } + + private static final class FakeSocket extends Socket { + private final InputStream in = new ByteArrayInputStream(new byte[0]); + private final OutputStream out = new ByteArrayOutputStream(); + private boolean closed; + + @Override + public void connect(SocketAddress endpoint, int timeout) {} + + @Override + public InputStream getInputStream() { + return in; + } + + @Override + public OutputStream getOutputStream() { + return out; + } + + @Override + public void setTcpNoDelay(boolean on) {} + + @Override + public void setKeepAlive(boolean on) {} + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void close() { + closed = true; + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/JdkTlsProviderTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/JdkTlsProviderTest.java new file mode 100644 index 0000000000..e6b55bc3ec --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/JdkTlsProviderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.SSLParameters; +import org.junit.jupiter.api.Test; + +/** + * Unit coverage for the TLS-provider seam: {@link JdkTlsProvider}, {@link TlsConnectionContext}, and + * {@link SslEngineTransports} argument handling. The end-to-end JDK TLS path (a real handshake through + * these types) is covered by the {@code TlsValidationTest} integration test, which uses properly-issued + * certificates; these unit tests cover the construction/configuration logic without a live socket. + */ +class JdkTlsProviderTest { + + @Test + void builderProducesUsableProvider() { + // No SSLContext supplied -> resolves to the default; the provider is available. + JdkTlsProvider provider = JdkTlsProvider.create(); + assertTrue(provider.isAvailable()); + assertThat(JdkTlsProvider.builder().build(), notNullValue()); + } + + @Test + void connectionContextRoundTrips() { + var ctx = TlsConnectionContext.builder() + .host("example.com") + .port(8443) + .alpnProtocols(List.of("h2", "http/1.1")) + .negotiationTimeoutMillis(1234) + .readTimeoutMillis(5678) + .tlsReadBufferSize(4096) + .tlsWriteBufferSize(2048) + .build(); + assertEquals("example.com", ctx.host()); + assertEquals(8443, ctx.port()); + assertEquals(List.of("h2", "http/1.1"), ctx.alpnProtocols()); + assertEquals(1234, ctx.negotiationTimeoutMillis()); + assertEquals(5678, ctx.readTimeoutMillis()); + assertEquals(4096, ctx.tlsReadBufferSize()); + assertEquals(2048, ctx.tlsWriteBufferSize()); + } + + @Test + void connectionContextAlpnNeverNull() { + // ALPN defaults to an empty (never null) list, and an explicit null is normalized. + assertEquals(List.of(), TlsConnectionContext.builder().build().alpnProtocols()); + assertEquals(List.of(), TlsConnectionContext.builder().alpnProtocols(null).build().alpnProtocols()); + } + + @Test + void connectionContextAlpnIsDefensivelyCopied() { + var mutable = new ArrayList<>(List.of("h2")); + var ctx = TlsConnectionContext.builder().alpnProtocols(mutable).build(); + mutable.add("http/1.1"); + assertEquals(List.of("h2"), ctx.alpnProtocols(), "context must not reflect later mutation of the source list"); + } + + @Test + void connectClosesSocketWhenEngineSetupFails() throws IOException { + // Bad SSLParameters make createEngine().setSSLParameters() throw IllegalArgumentException before + // the transport takes ownership. The provider must close the supplied socket before rethrowing + // (TlsProvider contract), not leak it. ALPN != http/1.1 forces the SSLEngine path. + assertSocketClosedOnSetupFailure(List.of("h2")); + } + + @Test + void connectClosesSocketWhenSslSocketSetupFails() throws IOException { + // Same, on the SSLSocket fast path (http/1.1-only over a plain socket). + assertSocketClosedOnSetupFailure(List.of("http/1.1")); + } + + private void assertSocketClosedOnSetupFailure(List alpn) throws IOException { + try (ServerSocket server = new ServerSocket(0, 1, InetAddress.getLoopbackAddress()); + Socket socket = new Socket(InetAddress.getLoopbackAddress(), server.getLocalPort()); + // Complete the TCP connect so the client socket is genuinely connected. + Socket accepted = server.accept()) { + SSLParameters bad = new SSLParameters(); + bad.setProtocols(new String[] {"NoSuchTLSProtocol"}); // rejected by the JSSE engine/socket + var ctx = TlsConnectionContext.builder() + .host(InetAddress.getLoopbackAddress().getHostAddress()) + .port(server.getLocalPort()) + .alpnProtocols(alpn) + .negotiationTimeoutMillis(1000) + .tlsReadBufferSize(16384) + .tlsWriteBufferSize(16384) + .socket(socket) + .build(); + var provider = JdkTlsProvider.builder().sslParameters(bad).build(); + assertThrows(Exception.class, () -> provider.connect(ctx)); + assertTrue(socket.isClosed(), "connect() must close the supplied socket on setup failure"); + } + } + + @Test + void sslEngineTransportsRejectsNullEngine() { + // No engine and no socket/channel -> fails fast rather than NPEing deep in the transport. + assertThrows(Exception.class, + () -> SslEngineTransports.connect(TlsConnectionContext.builder().host("h").build(), null, null)); + } + + @Test + void tlsProviderIsAFunctionalInterface() { + // The SPI is a single-method type: a lambda is a complete provider. (Compile-time guarantee that + // an out-of-module provider needs only connect().) + AtomicInteger calls = new AtomicInteger(); + TlsProvider lambda = ctx -> { + calls.incrementAndGet(); + throw new IOException("sentinel"); + }; + assertThrows(IOException.class, + () -> lambda.connect(TlsConnectionContext.builder().host("h").build())); + assertEquals(1, calls.get()); + assertTrue(lambda.isAvailable(), "isAvailable defaults to true"); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/ProxyTunnelTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/ProxyTunnelTest.java new file mode 100644 index 0000000000..82f860d77d --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/ProxyTunnelTest.java @@ -0,0 +1,181 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpResponse; +import software.amazon.smithy.java.http.api.ModifiableHttpRequest; +import software.amazon.smithy.java.http.client.HttpCredentials; + +class ProxyTunnelTest { + + private static final Duration TIMEOUT = Duration.ofSeconds(5); + + @Test + void establishSuccessfulTunnel() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 Connection Established\r\n\r\n"); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, null, TIMEOUT); + + assertNotNull(result.socket()); + assertEquals(200, result.statusCode()); + + var request = socket.getRequest(); + + // CONNECT uses authority-form: CONNECT host:port HTTP/1.1 + assertTrue(request.startsWith("CONNECT example.com:443 HTTP/1.1\r\n"), "Request was: " + request); + } + + @Test + void tunnelFailsWithForbidden() throws IOException { + var socket = new FakeSocket("HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n"); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, null, TIMEOUT); + + assertNull(result.socket()); + assertEquals(403, result.statusCode()); + } + + @Test + void tunnelWithBasicAuth() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 Connection Established\r\n\r\n"); + var creds = new HttpCredentials.Basic("user", "pass", true); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, creds, TIMEOUT); + + assertNotNull(result.socket()); + assertEquals(200, result.statusCode()); + + var request = socket.getRequest().toLowerCase(); + assertTrue(request.contains("proxy-authorization: basic"), "Request was: " + socket.getRequest()); + } + + @Test + void tunnelAuthFailsAfter407() throws IOException { + var socket = new FakeSocket("HTTP/1.1 407 Proxy Authentication Required\r\nContent-Length: 0\r\n\r\n"); + var creds = new HttpCredentials.Basic("user", "pass", true); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, creds, TIMEOUT); + + assertNull(result.socket()); + assertEquals(407, result.statusCode()); + } + + @Test + void tunnelWithMultiRoundAuth() throws IOException { + var socket = new FakeSocket( + "HTTP/1.1 407 Proxy Authentication Required\r\nContent-Length: 0\r\n\r\n" + + "HTTP/1.1 200 Connection Established\r\n\r\n"); + var creds = new MultiRoundCredentials(); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, creds, TIMEOUT); + + assertNotNull(result.socket()); + assertEquals(200, result.statusCode()); + assertEquals(2, creds.callCount); + } + + @Test + void tunnelWithoutCredentialsOn407() throws IOException { + var socket = new FakeSocket("HTTP/1.1 407 Proxy Authentication Required\r\nContent-Length: 0\r\n\r\n"); + var result = HttpConnectionFactory.establishTunnel(socket, "example.com", 443, null, TIMEOUT); + + assertNull(result.socket()); + assertEquals(407, result.statusCode()); + } + + @Test + void tunnelIncludesHostHeader() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 Connection Established\r\n\r\n"); + HttpConnectionFactory.establishTunnel(socket, "example.com", 443, null, TIMEOUT); + var request = socket.getRequest(); + + // Host header is auto-generated from URI, check for lowercase + assertTrue(request.contains("host: example.com") || request.contains("Host: example.com"), + "Request was: " + request); + } + + @Test + void tunnelIncludesProxyConnectionHeader() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 Connection Established\r\n\r\n"); + HttpConnectionFactory.establishTunnel(socket, "example.com", 443, null, TIMEOUT); + var request = socket.getRequest(); + + // Check for the header (case may vary) + assertTrue(request.toLowerCase().contains("proxy-connection:"), + "Request was: " + request); + } + + static class MultiRoundCredentials implements HttpCredentials { + int callCount = 0; + + @Override + public boolean authenticate(ModifiableHttpRequest request, HttpResponse priorResponse) { + callCount++; + request.addHeader("Proxy-Authorization", "Round" + callCount); + return true; + } + } + + static final class FakeSocket extends Socket { + private final ByteArrayInputStream in; + private final ByteArrayOutputStream out; + private final InetAddress address; + + FakeSocket(String response) throws IOException { + this.in = new ByteArrayInputStream(response.getBytes(StandardCharsets.US_ASCII)); + this.out = new ByteArrayOutputStream(); + this.address = InetAddress.getByName("127.0.0.1"); + } + + @Override + public InputStream getInputStream() { + return in; + } + + @Override + public OutputStream getOutputStream() { + return out; + } + + @Override + public InetAddress getInetAddress() { + return address; + } + + @Override + public int getPort() { + return 8080; + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return null; + } + + @Override + public void setSoTimeout(int timeout) {} + + @Override + public int getSoTimeout() { + return 0; + } + + String getRequest() { + return out.toString(StandardCharsets.US_ASCII); + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/RouteTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/RouteTest.java new file mode 100644 index 0000000000..d4c869f7dd --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/RouteTest.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.client.ProxyConfiguration; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class RouteTest { + + @Test + void fromUriUsesDefaultPortForHttp() { + var route = Route.from(SmithyUri.of("http://example.com/path")); + + assertEquals(80, route.port()); + } + + @Test + void fromUriUsesDefaultPortForHttps() { + var route = Route.from(SmithyUri.of("https://example.com/path")); + + assertEquals(443, route.port()); + } + + @Test + void fromUriUsesExplicitPort() { + var route = Route.from(SmithyUri.of("https://example.com:8443/path")); + + assertEquals(8443, route.port()); + } + + @Test + void fromUriNormalizesHostToLowercase() { + var route = Route.from(SmithyUri.of("https://EXAMPLE.COM/path")); + + assertEquals("example.com", route.host()); + } + + @Test + void fromUriIgnoresPathAndQuery() { + var route1 = Route.from(SmithyUri.of("https://example.com/users?id=1")); + var route2 = Route.from(SmithyUri.of("https://example.com/posts?id=2")); + + assertEquals(route1, route2); + } + + @Test + void fromUriThrowsOnMissingScheme() { + assertThrows(IllegalArgumentException.class, + () -> Route.from(SmithyUri.of("example.com/path"))); + } + + @Test + void fromUriThrowsOnMissingHost() { + assertThrows(IllegalArgumentException.class, + () -> Route.from(SmithyUri.of("http:///path"))); + } + + @Test + void directThrowsOnInvalidScheme() { + assertThrows(IllegalArgumentException.class, + () -> Route.direct("ftp", "example.com", 21)); + } + + @Test + void directThrowsOnInvalidPort() { + assertThrows(IllegalArgumentException.class, + () -> Route.direct("http", "example.com", 0)); + assertThrows(IllegalArgumentException.class, + () -> Route.direct("http", "example.com", 70000)); + } + + @Test + void isSecureReturnsTrueForHttps() { + var route = Route.direct("https", "example.com", 443); + + assertTrue(route.isSecure()); + } + + @Test + void isSecureReturnsFalseForHttp() { + var route = Route.direct("http", "example.com", 80); + + assertFalse(route.isSecure()); + } + + @Test + void withProxyCreatesNewRouteWithProxy() { + var route = Route.direct("https", "example.com", 443); + var proxy = new ProxyConfiguration(SmithyUri.of("http://proxy:8080"), ProxyConfiguration.ProxyType.HTTP); + var proxied = route.withProxy(proxy); + + assertFalse(route.usesProxy()); + assertTrue(proxied.usesProxy()); + assertEquals(route.host(), proxied.host()); + } + + @Test + void withoutProxyCreatesNewRouteWithoutProxy() { + var proxy = new ProxyConfiguration(SmithyUri.of("http://proxy:8080"), ProxyConfiguration.ProxyType.HTTP); + var route = Route.viaProxy("https", "example.com", 443, proxy); + var direct = route.withoutProxy(); + + assertTrue(route.usesProxy()); + assertFalse(direct.usesProxy()); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/TlsProviderDiscoveryTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/TlsProviderDiscoveryTest.java new file mode 100644 index 0000000000..27ebd4cd99 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/TlsProviderDiscoveryTest.java @@ -0,0 +1,125 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +/** + * Covers {@link TlsProvider} ServiceLoader discovery and {@code smithy-java.tls-provider} opt-in. Two + * test providers are registered via {@code META-INF/services} in the test source set: + * {@link AvailableTestTlsProvider} and {@link UnavailableTestTlsProvider}. + */ +class TlsProviderDiscoveryTest { + + @AfterEach + void clearProperty() { + System.clearProperty(TlsProvider.PROVIDER_PROPERTY); + } + + @Test + void fromSystemPropertyNullWhenUnset() { + System.clearProperty(TlsProvider.PROVIDER_PROPERTY); + assertNull(TlsProvider.fromSystemProperty()); + } + + @Test + void fromSystemPropertyNullWhenBlank() { + System.setProperty(TlsProvider.PROVIDER_PROPERTY, " "); + assertNull(TlsProvider.fromSystemProperty()); + } + + @Test + void fromSystemPropertyResolvesRegisteredProvider() { + System.setProperty(TlsProvider.PROVIDER_PROPERTY, AvailableTestTlsProvider.class.getName()); + assertThat(TlsProvider.fromSystemProperty(), instanceOf(AvailableTestTlsProvider.class)); + } + + @Test + void byClassNameFindsAvailableProvider() { + TlsProvider provider = TlsProvider.byClassName( + AvailableTestTlsProvider.class.getName(), + getClass().getClassLoader()); + assertThat(provider, instanceOf(AvailableTestTlsProvider.class)); + } + + @Test + void byClassNameFallsBackWhenLoaderNull() { + // null loader -> uses TlsProvider's own loader (the GraalVM native-image case, where the + // thread-context loader may be null). Discovery must still succeed. + TlsProvider provider = TlsProvider.byClassName(AvailableTestTlsProvider.class.getName(), null); + assertThat(provider, instanceOf(AvailableTestTlsProvider.class)); + } + + @Test + void discoveryWorksWithNullContextClassLoader() { + // Simulate a runtime with no thread-context loader (as can happen under native-image): selection + // by system property must still resolve the registered provider via the interface's loader. + Thread current = Thread.currentThread(); + ClassLoader saved = current.getContextClassLoader(); + try { + current.setContextClassLoader(null); + System.setProperty(TlsProvider.PROVIDER_PROPERTY, AvailableTestTlsProvider.class.getName()); + assertThat(TlsProvider.fromSystemProperty(), instanceOf(AvailableTestTlsProvider.class)); + } finally { + current.setContextClassLoader(saved); + } + } + + @Test + void byClassNameRejectsUnavailableProvider() { + var ex = assertThrows(IllegalStateException.class, + () -> TlsProvider.byClassName( + UnavailableTestTlsProvider.class.getName(), + getClass().getClassLoader())); + assertThat(ex.getMessage(), containsString("unavailable")); + } + + @Test + void byClassNameErrorsOnUnknownProvider() { + var ex = assertThrows(IllegalStateException.class, + () -> TlsProvider.byClassName( + "com.example.NoSuchProvider", + getClass().getClassLoader())); + // The message must name the missing class and list what was actually discovered, to aid debugging. + assertThat(ex.getMessage(), containsString("com.example.NoSuchProvider")); + assertThat(ex.getMessage(), containsString(AvailableTestTlsProvider.class.getName())); + } + + @Test + void unavailableProviderReportsFalse() { + assertFalse(new UnavailableTestTlsProvider().isAvailable()); + assertTrue(new AvailableTestTlsProvider().isAvailable()); + } + + @Test + void supportsEpollDefaultsFalseForCustomProviders() { + // A custom provider must NOT silently opt into the internal epoll substrate (which would hand it + // a null socket). The default protects external/self-I/O providers. + assertFalse(new AvailableTestTlsProvider().supportsEpoll()); + } + + @Test + void builtInEngineProvidersSupportEpoll() { + // Engine-based providers consume the internal epoll channel via SslEngineTransports. + assertTrue(JdkTlsProvider.create().supportsEpoll()); + } + + @Test + void defaultProviderPropertyName() { + // Lock the documented property name so it cannot change silently. + assertEquals("smithy-java.tls-provider", TlsProvider.PROVIDER_PROPERTY); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/UnavailableTestTlsProvider.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/UnavailableTestTlsProvider.java new file mode 100644 index 0000000000..6270c5f2e6 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/connection/UnavailableTestTlsProvider.java @@ -0,0 +1,21 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.connection; + +import java.io.IOException; + +/** A discoverable {@link TlsProvider} that reports unavailable, to test the availability guard. */ +public final class UnavailableTestTlsProvider implements TlsProvider { + @Override + public boolean isAvailable() { + return false; + } + + @Override + public ConnectionTransport connect(TlsConnectionContext connection) throws IOException { + throw new IOException("unavailable"); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolverTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolverTest.java new file mode 100644 index 0000000000..875b05cf58 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/RoundRobinDnsResolverTest.java @@ -0,0 +1,112 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class RoundRobinDnsResolverTest { + + @Test + void rotatesAddressesPerHostname() throws Exception { + var addr1 = InetAddress.getByName("127.0.0.1"); + var addr2 = InetAddress.getByName("127.0.0.2"); + var addr3 = InetAddress.getByName("127.0.0.3"); + var resolver = DnsResolver.roundRobin(DnsResolver.staticMapping(Map.of( + "example.com", + List.of(addr1, addr2, addr3)))); + + assertEquals(List.of(addr1, addr2, addr3), resolver.resolve("example.com")); + assertEquals(List.of(addr2, addr3, addr1), resolver.resolve("example.com")); + assertEquals(List.of(addr3, addr1, addr2), resolver.resolve("example.com")); + assertEquals(List.of(addr1, addr2, addr3), resolver.resolve("example.com")); + } + + @Test + void rotatesHostnamesIndependently() throws Exception { + var addr1 = InetAddress.getByName("127.0.0.1"); + var addr2 = InetAddress.getByName("127.0.0.2"); + var addr3 = InetAddress.getByName("127.0.0.3"); + var addr4 = InetAddress.getByName("127.0.0.4"); + var resolver = DnsResolver.roundRobin(DnsResolver.staticMapping(Map.of( + "a.example.com", + List.of(addr1, addr2), + "b.example.com", + List.of(addr3, addr4)))); + + assertEquals(List.of(addr1, addr2), resolver.resolve("a.example.com")); + assertEquals(List.of(addr3, addr4), resolver.resolve("b.example.com")); + assertEquals(List.of(addr2, addr1), resolver.resolve("a.example.com")); + assertEquals(List.of(addr4, addr3), resolver.resolve("b.example.com")); + } + + @Test + void purgeCacheResetsRotation() throws Exception { + var addr1 = InetAddress.getByName("127.0.0.1"); + var addr2 = InetAddress.getByName("127.0.0.2"); + var resolver = DnsResolver.roundRobin(DnsResolver.staticMapping(Map.of( + "example.com", + List.of(addr1, addr2)))); + + assertEquals(List.of(addr1, addr2), resolver.resolve("example.com")); + assertEquals(List.of(addr2, addr1), resolver.resolve("example.com")); + + resolver.purgeCache("example.com"); + + assertEquals(List.of(addr1, addr2), resolver.resolve("example.com")); + } + + @Test + void delegatesFailureReportsAndCachePurges() throws Exception { + var addr = InetAddress.getByName("127.0.0.1"); + var delegate = new RecordingResolver(addr); + var resolver = DnsResolver.roundRobin(delegate); + + resolver.reportFailure(addr); + resolver.purgeCache("example.com"); + resolver.purgeCache(); + + assertEquals(1, delegate.failures); + assertEquals(1, delegate.hostnamePurges); + assertEquals(1, delegate.allPurges); + } + + private static final class RecordingResolver implements DnsResolver { + private final InetAddress address; + private int failures; + private int hostnamePurges; + private int allPurges; + + RecordingResolver(InetAddress address) { + this.address = address; + } + + @Override + public List resolve(String hostname) throws IOException { + return List.of(address); + } + + @Override + public void reportFailure(InetAddress address) { + failures++; + } + + @Override + public void purgeCache(String hostname) { + hostnamePurges++; + } + + @Override + public void purgeCache() { + allPurges++; + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolverTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolverTest.java new file mode 100644 index 0000000000..e41a3dec3f --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/StaticDnsResolverTest.java @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class StaticDnsResolverTest { + + @Test + void resolvesConfiguredHostname() throws Exception { + var addr = InetAddress.getLoopbackAddress(); + var resolver = new StaticDnsResolver(Map.of("example.com", List.of(addr))); + var result = resolver.resolve("example.com"); + + assertEquals(List.of(addr), result); + } + + @Test + void resolveIsCaseInsensitive() throws Exception { + var addr = InetAddress.getLoopbackAddress(); + var resolver = new StaticDnsResolver(Map.of("example.com", List.of(addr))); + + assertEquals(List.of(addr), resolver.resolve("EXAMPLE.COM")); + assertEquals(List.of(addr), resolver.resolve("Example.Com")); + } + + @Test + void throwsForUnknownHostname() { + var resolver = new StaticDnsResolver(Map.of("known.com", List.of(InetAddress.getLoopbackAddress()))); + + assertThrows(IOException.class, () -> resolver.resolve("unknown.com")); + } + + @Test + void returnsMultipleAddresses() throws Exception { + var addr1 = InetAddress.getByName("127.0.0.1"); + var addr2 = InetAddress.getByName("127.0.0.2"); + var resolver = new StaticDnsResolver(Map.of("example.com", List.of(addr1, addr2))); + var result = resolver.resolve("example.com"); + + assertEquals(2, result.size()); + assertEquals(addr1, result.get(0)); + assertEquals(addr2, result.get(1)); + } + + @Test + void ignoresEmptyMappings() { + var resolver = new StaticDnsResolver(Map.of("empty.com", List.of())); + + assertThrows(IOException.class, () -> resolver.resolve("empty.com")); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolverTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolverTest.java new file mode 100644 index 0000000000..2604c86faf --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/dns/SystemDnsResolverTest.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.dns; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class SystemDnsResolverTest { + + @Test + void resolvesLocalhost() throws Exception { + var result = SystemDnsResolver.INSTANCE.resolve("localhost"); + + assertFalse(result.isEmpty()); + assertTrue(result.get(0).isLoopbackAddress()); + } + + @Test + void throwsForUnknownHost() { + assertThrows(IOException.class, + () -> SystemDnsResolver.INSTANCE.resolve("this.host.definitely.does.not.exist.invalid")); + } + + @Test + void resolvesIpAddressDirectly() throws Exception { + var result = SystemDnsResolver.INSTANCE.resolve("127.0.0.1"); + + assertFalse(result.isEmpty()); + assertTrue(result.get(0).isLoopbackAddress()); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedEncodingFuzzTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedEncodingFuzzTest.java new file mode 100644 index 0000000000..14b36f56f9 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedEncodingFuzzTest.java @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import com.code_intelligence.jazzer.junit.FuzzTest; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Fuzz tests for HTTP/1.1 chunked transfer encoding. + */ +class ChunkedEncodingFuzzTest { + + private static final int MAX_FUZZ_INPUT = 512; + + // --- Crash safety: random bytes as chunked input --- + + @FuzzTest + void fuzzChunkedInputDecode(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + var bis = new UnsyncBufferedInputStream(new ByteArrayInputStream(data), 1024); + var chunked = new ChunkedInputStream(bis); + try { + chunked.transferTo(OutputStream.nullOutputStream()); + } catch (IOException ignored) {} + } + + // --- Round-trip: write chunked → read chunked → verify identity --- + + @FuzzTest + void fuzzChunkedRoundTrip(byte[] data) throws IOException { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + + // Write through ChunkedOutputStream + var wireBuffer = new ByteArrayOutputStream(); + var bos = new UnsyncBufferedOutputStream(wireBuffer, 1024); + var chunkedOut = new ChunkedOutputStream(bos, 64); + chunkedOut.write(data); + chunkedOut.close(); + + // Read back through ChunkedInputStream + byte[] wire = wireBuffer.toByteArray(); + var bis = new UnsyncBufferedInputStream(new ByteArrayInputStream(wire), 1024); + var chunkedIn = new ChunkedInputStream(bis); + var result = new ByteArrayOutputStream(); + chunkedIn.transferTo(result); + byte[] decoded = result.toByteArray(); + + assertArrayEquals(data, decoded, "Chunked round-trip mismatch"); + } + +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStreamTest.java new file mode 100644 index 0000000000..4d083c2635 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedInputStreamTest.java @@ -0,0 +1,326 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class ChunkedInputStreamTest { + + private ChunkedInputStream chunked(String data) { + var bytes = data.getBytes(StandardCharsets.US_ASCII); + return new ChunkedInputStream(new UnsyncBufferedInputStream(new ByteArrayInputStream(bytes), 256)); + } + + @Test + void readsSingleChunk() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertArrayEquals("hello".getBytes(), result); + } + + @Test + void readsMultipleChunks() throws IOException { + var stream = chunked("5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertArrayEquals("hello world".getBytes(), result); + } + + @Test + void readsEmptyBody() throws IOException { + var stream = chunked("0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertEquals(0, result.length); + } + + @Test + void readsSingleByte() throws IOException { + var stream = chunked("3\r\nabc\r\n0\r\n\r\n"); + + assertEquals('a', stream.read()); + assertEquals('b', stream.read()); + assertEquals('c', stream.read()); + assertEquals(-1, stream.read()); + } + + @Test + void readsUppercaseHex() throws IOException { + var stream = chunked("A\r\n0123456789\r\n0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertEquals(10, result.length); + } + + @Test + void readsLowercaseHex() throws IOException { + var stream = chunked("a\r\n0123456789\r\n0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertEquals(10, result.length); + } + + @Test + void ignoresChunkExtensions() throws IOException { + var stream = chunked("5;name=value\r\nhello\r\n0\r\n\r\n"); + + byte[] result = stream.readAllBytes(); + + assertArrayEquals("hello".getBytes(), result); + } + + @Test + void parsesTrailers() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\nX-Checksum: abc123\r\n\r\n"); + stream.readAllBytes(); + + var trailers = stream.getTrailers(); + + assertEquals("abc123", trailers.firstValue("x-checksum")); + } + + @Test + void parsesMultipleTrailers() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\nX-Foo: bar\r\nX-Baz: qux\r\n\r\n"); + stream.readAllBytes(); + + var trailers = stream.getTrailers(); + + assertEquals("bar", trailers.firstValue("x-foo")); + assertEquals("qux", trailers.firstValue("x-baz")); + } + + @Test + void trailersNullBeforeEof() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\nX-Foo: bar\r\n\r\n"); + + assertNull(stream.getTrailers()); + } + + @Test + void trailersNullWhenNonePresent() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + stream.readAllBytes(); + + assertNull(stream.getTrailers()); + } + + @Test + void availableReturnsChunkRemaining() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + stream.read(); // read 'h' + + int available = stream.available(); + + assertEquals(4, available); + } + + @Test + void skipSkipsBytes() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + + long skipped = stream.skip(3); + + assertEquals(3, skipped); + assertEquals('l', stream.read()); + assertEquals('o', stream.read()); + } + + @Test + void closeDrainsAndParsesTrailers() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\nX-Foo: bar\r\n\r\n"); + stream.close(); + + var trailers = stream.getTrailers(); + + assertEquals("bar", trailers.firstValue("x-foo")); + } + + @Test + void closeIsIdempotent() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + + stream.close(); + stream.close(); + + assertEquals(-1, stream.read()); + } + + @Test + void throwsOnInvalidHex() { + var stream = chunked("xyz\r\nhello\r\n0\r\n\r\n"); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnMissingCrlf() { + var stream = chunked("5\r\nhelloX"); + + assertThrows(IOException.class, stream::readAllBytes); + } + + @Test + void throwsOnUnexpectedEofInSingleByteRead() { + var stream = chunked("5\r\nhi"); + + assertThrows(IOException.class, () -> { + stream.read(); + stream.read(); + stream.read(); // expects 5 bytes but only 2 available + }); + } + + @Test + void throwsOnUnexpectedEofInBulkRead() { + var stream = chunked("5\r\nhi"); + + assertThrows(IOException.class, () -> { + // First read returns 2 bytes, second read hits EOF + byte[] buf = new byte[10]; + stream.read(buf, 0, 10); + stream.read(buf, 0, 10); + }); + } + + @Test + void readReturnsNegativeOneAfterClose() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + stream.close(); + + assertEquals(-1, stream.read()); + } + + @Test + void readReturnsNegativeOneAfterEof() throws IOException { + var stream = chunked("0\r\n\r\n"); + stream.readAllBytes(); + + assertEquals(-1, stream.read()); + } + + @Test + void bulkReadReturnsNegativeOneAfterEof() throws IOException { + var stream = chunked("0\r\n\r\n"); + stream.readAllBytes(); + + assertEquals(-1, stream.read(new byte[10], 0, 10)); + } + + @Test + void skipReturnsZeroAfterEof() throws IOException { + var stream = chunked("0\r\n\r\n"); + stream.readAllBytes(); + + assertEquals(0, stream.skip(10)); + } + + @Test + void skipReturnsZeroWhenClosed() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + stream.close(); + + assertEquals(0, stream.skip(10)); + } + + @Test + void skipStopsAtEof() throws IOException { + var stream = chunked("3\r\nabc\r\n0\r\n\r\n"); + + long skipped = stream.skip(100); + + assertEquals(3, skipped); + } + + @Test + void availableReturnsZeroAfterEof() throws IOException { + var stream = chunked("0\r\n\r\n"); + stream.readAllBytes(); + + assertEquals(0, stream.available()); + } + + @Test + void availableReturnsZeroWhenClosed() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + stream.close(); + + assertEquals(0, stream.available()); + } + + @Test + void availableReturnsZeroBeforeFirstRead() throws IOException { + var stream = chunked("5\r\nhello\r\n0\r\n\r\n"); + + assertEquals(0, stream.available()); + } + + @Test + void throwsOnEmptyChunkSizeLine() { + var stream = chunked("\r\nhello\r\n0\r\n\r\n"); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnMissingChunkSize() { + var stream = chunked(";extension\r\nhello\r\n0\r\n\r\n"); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnInvalidCrlfAfterChunk() { + var stream = chunked("5\r\nhello\n\n0\r\n\r\n"); + + assertThrows(IOException.class, stream::readAllBytes); + } + + @Test + void throwsOnTruncatedCrlfAfterChunk() { + var stream = chunked("5\r\nhello\r"); + + assertThrows(IOException.class, stream::readAllBytes); + } + + @Test + void throwsOnChunkSizeExceedsMax() { + // 0x100000000 = 4GB, way over the 1MB default max + var stream = chunked("100000000\r\n"); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnChunkSizeOverflow() { + // 17 hex digits would overflow a long (max is 16 hex digits = 64 bits) + var stream = chunked("FFFFFFFFFFFFFFFFF\r\n"); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnInvalidTrailerLine() { + // Trailer line without colon is invalid + var stream = chunked("5\r\nhello\r\n0\r\ninvalidtrailer\r\n\r\n"); + + assertThrows(IOException.class, stream::readAllBytes); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStreamTest.java new file mode 100644 index 0000000000..2b12731b2f --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/ChunkedOutputStreamTest.java @@ -0,0 +1,167 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpHeaders; + +class ChunkedOutputStreamTest { + + private ChunkedOutputStream chunked(ByteArrayOutputStream baos, int chunkSize) { + return new ChunkedOutputStream(new UnsyncBufferedOutputStream(baos, 1024), chunkSize); + } + + private ChunkedOutputStream chunked(ByteArrayOutputStream baos) { + return new ChunkedOutputStream(new UnsyncBufferedOutputStream(baos, 1024)); + } + + @Test + void writesSingleChunk() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write("hello".getBytes()); + stream.close(); + + assertEquals("5\r\nhello\r\n0\r\n\r\n", baos.toString()); + } + + @Test + void writesMultipleChunks() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 5); + stream.write("hello world".getBytes()); + stream.close(); + + assertEquals("5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n", baos.toString()); + } + + @Test + void writesEmptyBody() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos); + stream.close(); + + assertEquals("0\r\n\r\n", baos.toString()); + } + + @Test + void writesSingleBytes() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write('a'); + stream.write('b'); + stream.write('c'); + stream.close(); + + assertEquals("3\r\nabc\r\n0\r\n\r\n", baos.toString()); + } + + @Test + void flushWritesChunk() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write("hello".getBytes()); + stream.flush(); + + assertEquals("5\r\nhello\r\n", baos.toString()); + } + + @Test + void writesTrailers() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write("hello".getBytes()); + stream.setTrailers(HttpHeaders.of(Map.of("x-checksum", List.of("abc123")))); + stream.close(); + + assertEquals("5\r\nhello\r\n0\r\nx-checksum: abc123\r\n\r\n", baos.toString()); + } + + @Test + void writesMultipleTrailers() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write("hi".getBytes()); + stream.setTrailers(HttpHeaders.of(Map.of( + "x-foo", + List.of("bar"), + "x-baz", + List.of("qux")))); + stream.close(); + + String result = baos.toString(); + assertTrue(result.startsWith("2\r\nhi\r\n0\r\n")); + assertTrue(result.contains("x-foo: bar\r\n")); + assertTrue(result.contains("x-baz: qux\r\n")); + assertTrue(result.endsWith("\r\n\r\n")); + } + + @Test + void writesMultiValueTrailer() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 1024); + stream.write("hi".getBytes()); + stream.setTrailers(HttpHeaders.of(Map.of("x-multi", List.of("a", "b")))); + stream.close(); + + String result = baos.toString(); + assertTrue(result.contains("x-multi: a\r\n")); + assertTrue(result.contains("x-multi: b\r\n")); + } + + @Test + void singleByteWriteFlushesWhenBufferFull() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos, 3); + stream.write('a'); + stream.write('b'); + stream.write('c'); // buffer full, triggers flush + stream.flush(); // need to flush the underlying buffer too + + assertEquals("3\r\nabc\r\n", baos.toString()); + } + + @Test + void closeIsIdempotent() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos); + stream.write("hi".getBytes()); + stream.close(); + stream.close(); + + assertEquals("2\r\nhi\r\n0\r\n\r\n", baos.toString()); + } + + @Test + void throwsAfterClose() throws IOException { + var baos = new ByteArrayOutputStream(); + var stream = chunked(baos); + stream.close(); + + assertThrows(IOException.class, () -> stream.write(1)); + } + + @Test + void throwsOnInvalidChunkSize() { + var baos = new ByteArrayOutputStream(); + var delegate = new UnsyncBufferedOutputStream(baos, 1024); + + assertThrows(IllegalArgumentException.class, () -> new ChunkedOutputStream(delegate, 0)); + } + + @Test + void throwsOnNullDelegate() { + assertThrows(NullPointerException.class, () -> new ChunkedOutputStream(null)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/FailingOutputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/FailingOutputStreamTest.java new file mode 100644 index 0000000000..5ae72531a1 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/FailingOutputStreamTest.java @@ -0,0 +1,42 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class FailingOutputStreamTest { + + @Test + void writeThrowsConfiguredException() { + var expected = new IOException("test error"); + var stream = new FailingOutputStream(expected); + var thrown = assertThrows(IOException.class, () -> stream.write(1)); + + assertSame(expected, thrown); + } + + @Test + void flushThrowsConfiguredException() { + var expected = new IOException("test error"); + var stream = new FailingOutputStream(expected); + var thrown = assertThrows(IOException.class, stream::flush); + + assertSame(expected, thrown); + } + + @Test + void closeIsNoOp() throws IOException { + var expected = new IOException("test error"); + var stream = new FailingOutputStream(expected); + + // close() should not throw - it's a no-op to avoid masking the real error + stream.close(); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ConnectionTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ConnectionTest.java new file mode 100644 index 0000000000..ccad355b7f --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ConnectionTest.java @@ -0,0 +1,304 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.connection.ConnectionTransport; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class H1ConnectionTest { + + private static final Route TEST_ROUTE = Route.direct("https", "example.com", 443); + private static final Duration READ_TIMEOUT = Duration.ofSeconds(5); + + @Test + void createsConnectionSuccessfully() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertTrue(connection.isActive()); + assertEquals(HttpVersion.HTTP_1_1, connection.httpVersion()); + assertEquals(TEST_ROUTE, connection.route()); + } + + @Test + void createsExchangeSuccessfully() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/test")); + var exchange = connection.newExchange(request, RequestOptions.defaults()); + + assertNotNull(exchange); + exchange.close(); + } + + @Test + void throwsOnConcurrentExchange() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/test")); + + connection.newExchange(request, RequestOptions.defaults()); + + assertThrows(IOException.class, () -> connection.newExchange(request, RequestOptions.defaults())); + } + + @Test + void throwsOnClosedConnection() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/test")); + + connection.close(); + + assertThrows(IOException.class, () -> connection.newExchange(request, RequestOptions.defaults())); + } + + @Test + void isActiveReturnsFalseAfterClose() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.close(); + + assertFalse(connection.isActive()); + } + + @Test + void isActiveReturnsFalseWhenKeepAliveDisabled() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.setKeepAlive(false); + + assertFalse(connection.isActive()); + } + + @Test + void validateForReuseReturnsTrueForHealthyConnection() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertTrue(connection.validateForReuse()); + } + + @Test + void validateForReuseReturnsFalseWhenInactive() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.markInactive(); + + assertFalse(connection.validateForReuse()); + } + + @Test + void validateForReuseReturnsFalseWhenKeepAliveDisabled() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.setKeepAlive(false); + + assertFalse(connection.validateForReuse()); + } + + @Test + void validateForReuseReturnsFalseWhenSocketClosed() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + socket.close(); + + assertFalse(connection.validateForReuse()); + assertFalse(connection.isActive()); + } + + @Test + void validateForReuseReturnsFalseWhenDataAvailableOnIdleConnection() throws IOException { + var socket = new FakeSocket("HTTP/1.1 200 OK\r\n"); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertFalse(connection.validateForReuse()); + assertFalse(connection.isActive()); + } + + @Test + void validateForReuseReturnsFalseWhenAvailableThrows() throws IOException { + var socket = new FailingAvailableSocket(); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertFalse(connection.validateForReuse()); + assertFalse(connection.isActive()); + } + + @Test + void sslSessionReturnsNullForPlainSocket() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertNull(connection.sslSession()); + } + + @Test + void negotiatedProtocolReturnsNullForPlainSocket() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertNull(connection.negotiatedProtocol()); + } + + @Test + void setAndGetSocketTimeout() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.setSocketTimeout(1000); + + assertEquals(1000, connection.getSocketTimeout()); + } + + @Test + void keepAliveDefaultsToTrue() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + + assertTrue(connection.isKeepAlive()); + } + + @Test + void markInactiveSetsConnectionInactive() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + connection.markInactive(); + + assertFalse(connection.isActive()); + } + + @Test + void nullReadTimeoutDoesNotSetSocketTimeout() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, null); + + assertEquals(0, connection.getSocketTimeout()); + } + + @Test + void zeroReadTimeoutDoesNotSetSocketTimeout() throws IOException { + var socket = new FakeSocket(""); + var connection = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, Duration.ZERO); + + assertEquals(0, connection.getSocketTimeout()); + } + + static class FakeSocket extends Socket { + private final ByteArrayInputStream in; + private final ByteArrayOutputStream out; + private final InetAddress address; + private int soTimeout = 0; + private boolean closed = false; + + FakeSocket(String response) throws IOException { + this.in = new ByteArrayInputStream(response.getBytes(StandardCharsets.US_ASCII)); + this.out = new ByteArrayOutputStream(); + this.address = InetAddress.getByName("127.0.0.1"); + } + + @Override + public InputStream getInputStream() { + return in; + } + + @Override + public OutputStream getOutputStream() { + return out; + } + + @Override + public InetAddress getInetAddress() { + return address; + } + + @Override + public int getPort() { + return 443; + } + + @Override + public void setSoTimeout(int timeout) { + this.soTimeout = timeout; + } + + @Override + public int getSoTimeout() { + return soTimeout; + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public boolean isInputShutdown() { + return closed; + } + + @Override + public boolean isOutputShutdown() { + return closed; + } + + @Override + public void close() { + closed = true; + } + + String outputString() { + return out.toString(StandardCharsets.US_ASCII); + } + } + + static final class FailingAvailableSocket extends FakeSocket { + FailingAvailableSocket() throws IOException { + super(""); + } + + @Override + public InputStream getInputStream() { + return new InputStream() { + @Override + public int read() { + return -1; + } + + @Override + public int available() throws IOException { + throw new IOException("boom"); + } + }; + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ExchangeTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ExchangeTest.java new file mode 100644 index 0000000000..046ec473f3 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1ExchangeTest.java @@ -0,0 +1,488 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.http.api.HttpHeaders; +import software.amazon.smithy.java.http.api.HttpRequest; +import software.amazon.smithy.java.http.api.HttpVersion; +import software.amazon.smithy.java.http.client.RequestOptions; +import software.amazon.smithy.java.http.client.connection.ConnectionTransport; +import software.amazon.smithy.java.http.client.connection.Route; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.io.uri.SmithyUri; + +class H1ExchangeTest { + + private static final Route TEST_ROUTE = Route.direct("https", "example.com", 443); + private static final Duration READ_TIMEOUT = Duration.ofSeconds(5); + + private H1Connection connection(String response) throws IOException { + var socket = new H1ConnectionTest.FakeSocket(response); + return new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + } + + private HttpRequest getRequest() { + return HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/test")); + } + + private HttpRequest headRequest() { + return HttpRequest.create() + .setMethod("HEAD") + .setUri(SmithyUri.of("https://example.com/test")); + } + + @Test + void connectionCloseDisablesKeepAlive() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + exchange.responseHeaders(); + + assertFalse(conn.isKeepAlive(), "Connection: close should disable keep-alive"); + exchange.close(); + } + + @Test + void connectionKeepAliveWithoutCloseKeepsAlive() throws IOException { + var conn = connection( + "HTTP/1.0 200 OK\r\n" + + "Connection: keep-alive\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + exchange.responseHeaders(); + + assertTrue(conn.isKeepAlive(), + "Connection: keep-alive should enable keep-alive for HTTP/1.0"); + exchange.close(); + } + + @Test + void http10DefaultsToConnectionClose() throws IOException { + var conn = connection( + "HTTP/1.0 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + exchange.responseHeaders(); + + assertFalse(conn.isKeepAlive(), + "HTTP/1.0 should default to Connection: close"); + exchange.close(); + } + + @Test + void http11DefaultsToKeepAlive() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + exchange.responseHeaders(); + + assertTrue(conn.isKeepAlive(), + "HTTP/1.1 should default to keep-alive"); + exchange.close(); + } + + @Test + void parsesResponseVersion() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + + assertEquals(HttpVersion.HTTP_1_1, exchange.responseVersion()); + exchange.close(); + } + + @Test + void parsesResponseBody() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + var body = new String(exchange.responseBody().readAllBytes()); + + assertEquals("hello", body); + exchange.close(); + } + + @Test + void transfersFixedLengthResponseBodyAndReusesConnection() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + var out = new ByteArrayOutputStream(); + + assertEquals(5, first.responseBody().transferTo(out)); + assertEquals("hello", out.toString(java.nio.charset.StandardCharsets.US_ASCII)); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void fixedLengthTransferToThrowsOnPrematureEof() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "he"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + + assertThrows(IOException.class, () -> exchange.responseBody().transferTo(OutputStream.nullOutputStream())); + } + + @Test + void acceptsMatchingDuplicateContentLengthHeaders() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + + assertEquals(5L, exchange.responseHeaders().contentLength()); + assertEquals("hello", new String(exchange.responseBody().readAllBytes())); + exchange.close(); + } + + @Test + void rejectsConflictingDuplicateContentLengthHeaders() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "Content-Length: 6\r\n" + + "\r\n" + + "hello"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + + assertThrows(IOException.class, exchange::responseHeaders); + } + + @Test + void readsFixedLengthResponseBodyAsChannel() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + var out = new ByteArrayOutputStream(); + + Channels.newInputStream(exchange.responseBodyChannel()).transferTo(out); + + assertEquals("hello", out.toString(java.nio.charset.StandardCharsets.US_ASCII)); + } + + @Test + void responseBodyChannelReleasesConnectionAtEof() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + var channel = first.responseBodyChannel(); + ByteBuffer dst = ByteBuffer.allocate(16); + assertEquals(5, channel.read(dst)); + assertEquals(-1, channel.read(dst.clear())); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void responseBodyChannelCloseDrainsOnlyRemainingFixedLengthBytes() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + var channel = first.responseBodyChannel(); + ByteBuffer dst = ByteBuffer.allocate(2); + assertEquals(2, channel.read(dst)); + channel.close(); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void responseBodyChannelThrowsOnPrematureEof() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "he"); + + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + var channel = exchange.responseBodyChannel(); + ByteBuffer dst = ByteBuffer.allocate(16); + assertEquals(2, channel.read(dst)); + + assertThrows(IOException.class, () -> channel.read(dst.clear())); + assertThrows(IOException.class, channel::close); + } + + @Test + void exposesCachedContentHeaders() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/plain\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello"); + var exchange = conn.newExchange(getRequest(), RequestOptions.defaults()); + + assertEquals("text/plain", exchange.responseHeaders().contentType()); + assertEquals(5L, exchange.responseHeaders().contentLength()); + exchange.close(); + } + + @Test + void discardsFixedLengthBodyWithoutOpeningResponseStream() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "hello" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(200, first.responseStatusCode()); + first.discardResponseBody(); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void discardsChunkedBodyWithoutOpeningResponseStream() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Transfer-Encoding: chunked\r\n" + + "\r\n" + + "5;ignored=extension\r\n" + + "hello\r\n" + + "0\r\n" + + "Trailer: value\r\n" + + "\r\n" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(200, first.responseStatusCode()); + first.discardResponseBody(); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void headResponseIgnoresContentLengthWhenCreatingBody() throws IOException { + var conn = connection( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(headRequest(), RequestOptions.defaults()); + assertEquals(-1, first.responseBody().read()); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, second.responseStatusCode()); + second.close(); + } + + @Test + void noBodyStatusIgnoresContentLengthWhenDiscarding() throws IOException { + var conn = connection( + "HTTP/1.1 204 No Content\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + + var first = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(204, first.responseStatusCode()); + first.discardResponseBody(); + + var second = conn.newExchange(getRequest(), RequestOptions.defaults()); + assertEquals(200, second.responseStatusCode()); + second.close(); + } + + @Test + void expectContinueFinalResponseSkipsRequestBodyAndReturnsResponse() throws IOException { + var socket = new H1ConnectionTest.FakeSocket( + "HTTP/1.1 413 Payload Too Large\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var conn = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("POST") + .setUri(SmithyUri.of("https://example.com/test")) + .setHeaders(HttpHeaders.of(Map.of("Expect", List.of("100-continue")))) + .setBody(DataStream.ofString("request-body")); + + var exchange = conn.newExchange(request, RequestOptions.defaults()); + exchange.writeRequestBody(request.body()); + + assertEquals(413, exchange.responseStatusCode()); + assertFalse(socket.outputString().contains("request-body")); + exchange.close(); + } + + @Test + void expectContinueOverrideTrueAddsHeaderAndWaitsForContinue() throws IOException { + // Server replies 100 Continue, then the final 200 once the body is sent. + var socket = new H1ConnectionTest.FakeSocket( + "HTTP/1.1 100 Continue\r\n" + + "\r\n" + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var conn = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + // Request does NOT carry an Expect header; the override forces it. + var request = HttpRequest.create() + .setMethod("POST") + .setUri(SmithyUri.of("https://example.com/test")) + .setBody(DataStream.ofString("request-body")); + var options = RequestOptions.builder().expectContinue(true).build(); + + var exchange = conn.newExchange(request, options); + exchange.writeRequestBody(request.body()); + + assertEquals(200, exchange.responseStatusCode()); + var written = socket.outputString(); + assertTrue(written.toLowerCase().contains("expect: 100-continue"), "Expect header should be on the wire"); + // 100 Continue was received, so the body is sent. + assertTrue(written.contains("request-body")); + exchange.close(); + } + + @Test + void expectContinueOverrideFalseStripsHeaderAndSkipsHandshake() throws IOException { + // Only a final response is queued: if the client wrongly waited for 100 Continue it would + // consume this 200 as the interim response and misbehave. It must send the body immediately. + var socket = new H1ConnectionTest.FakeSocket( + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"); + var conn = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + // Request carries Expect: 100-continue; the override suppresses it. + var request = HttpRequest.create() + .setMethod("POST") + .setUri(SmithyUri.of("https://example.com/test")) + .setHeaders(HttpHeaders.of(Map.of("Expect", List.of("100-continue")))) + .setBody(DataStream.ofString("request-body")); + var options = RequestOptions.builder().expectContinue(false).build(); + + var exchange = conn.newExchange(request, options); + exchange.writeRequestBody(request.body()); + + assertEquals(200, exchange.responseStatusCode()); + var written = socket.outputString(); + assertFalse(written.toLowerCase().contains("expect:"), "Expect header should be suppressed"); + assertTrue(written.contains("request-body")); + exchange.close(); + } + + @Test + void unwrapsIoExceptionFromHeaderConsumer() throws IOException { + var socket = new H1ConnectionTest.FakeSocket("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") { + @Override + public OutputStream getOutputStream() { + return new OutputStream() { + @Override + public void write(int b) throws IOException { + throw new IOException("boom"); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + throw new IOException("boom"); + } + }; + } + }; + var conn = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/test")) + .setHeaders(HttpHeaders.of(Map.of("X-Big", List.of("x".repeat(9000))))); + + var thrown = assertThrows(IOException.class, () -> conn.newExchange(request, RequestOptions.defaults())); + assertEquals("boom", thrown.getMessage()); + } + + @Test + void writesRawPathAndQueryInRequestLine() throws IOException { + var socket = new H1ConnectionTest.FakeSocket("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + var conn = new H1Connection(ConnectionTransport.of(socket), TEST_ROUTE, READ_TIMEOUT); + var request = HttpRequest.create() + .setMethod("GET") + .setUri(SmithyUri.of("https://example.com/a%2Fb?prefix=x%2Fy")); + + var exchange = conn.newExchange(request, RequestOptions.defaults()); + exchange.responseStatusCode(); + + assertTrue(socket.outputString().startsWith("GET /a%2Fb?prefix=x%2Fy HTTP/1.1\r\n")); + exchange.close(); + } + +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1UtilsTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1UtilsTest.java new file mode 100644 index 0000000000..44cd12687c --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/H1UtilsTest.java @@ -0,0 +1,127 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.http.api.HeaderName; +import software.amazon.smithy.java.http.api.HttpHeaders; + +class H1UtilsTest { + + static Stream knownHeaders() { + return Stream.of( + // Common headers + Arguments.of("date", HeaderName.DATE.name()), + Arguments.of("vary", HeaderName.VARY.name()), + Arguments.of("etag", HeaderName.ETAG.name()), + Arguments.of("server", HeaderName.SERVER.name()), + Arguments.of("trailer", HeaderName.TRAILER.name()), + Arguments.of("expires", HeaderName.EXPIRES.name()), + Arguments.of("upgrade", HeaderName.UPGRADE.name()), + Arguments.of("location", HeaderName.LOCATION.name()), + Arguments.of("connection", HeaderName.CONNECTION.name()), + Arguments.of("keep-alive", HeaderName.KEEP_ALIVE.name()), + Arguments.of("set-cookie", HeaderName.SET_COOKIE.name()), + Arguments.of("content-type", HeaderName.CONTENT_TYPE.name()), + Arguments.of("cache-control", HeaderName.CACHE_CONTROL.name()), + Arguments.of("last-modified", HeaderName.LAST_MODIFIED.name()), + Arguments.of("content-range", HeaderName.CONTENT_RANGE.name()), + Arguments.of("accept-ranges", HeaderName.ACCEPT_RANGES.name()), + Arguments.of("content-length", HeaderName.CONTENT_LENGTH.name()), + Arguments.of("content-encoding", HeaderName.CONTENT_ENCODING.name()), + Arguments.of("x-amzn-requestid", HeaderName.X_AMZN_REQUESTID.name()), + Arguments.of("x-amz-request-id", HeaderName.X_AMZ_REQUEST_ID.name()), + Arguments.of("x-amz-checksum-crc32", HeaderName.X_AMZ_CHECKSUM_CRC32.name()), + Arguments.of("x-amz-checksum-crc32c", HeaderName.X_AMZ_CHECKSUM_CRC32C.name()), + Arguments.of("x-amz-checksum-crc64nvme", HeaderName.X_AMZ_CHECKSUM_CRC64NVME.name()), + Arguments.of("x-amz-checksum-sha1", HeaderName.X_AMZ_CHECKSUM_SHA1.name()), + Arguments.of("x-amz-checksum-sha256", HeaderName.X_AMZ_CHECKSUM_SHA256.name()), + Arguments.of("www-authenticate", HeaderName.WWW_AUTHENTICATE.name()), + Arguments.of("proxy-connection", HeaderName.PROXY_CONNECTION.name()), + Arguments.of("transfer-encoding", HeaderName.TRANSFER_ENCODING.name()), + Arguments.of("proxy-authenticate", HeaderName.PROXY_AUTHENTICATE.name())); + } + + @ParameterizedTest + @MethodSource("knownHeaders") + void internsKnownHeader(String header, String expected) { + byte[] buf = header.getBytes(StandardCharsets.US_ASCII); + String result = HeaderName.canonicalize(buf, 0, buf.length); + + assertSame(expected, result); + } + + @ParameterizedTest + @MethodSource("knownHeaders") + void internsKnownHeaderCaseInsensitive(String header, String expected) { + byte[] buf = header.toUpperCase().getBytes(StandardCharsets.US_ASCII); + String result = HeaderName.canonicalize(buf, 0, buf.length); + + assertSame(expected, result); + } + + @Test + void returnsNewStringForUnknownHeader() { + byte[] buf = "x-custom".getBytes(StandardCharsets.US_ASCII); + String result = HeaderName.canonicalize(buf, 0, buf.length); + + assertEquals("x-custom", result); + } + + @Test + void returnsNewStringForUnknownLengthMatch() { + // Same length as "date" but different content + byte[] buf = "test".getBytes(StandardCharsets.US_ASCII); + String result = HeaderName.canonicalize(buf, 0, buf.length); + + assertEquals("test", result); + } + + @Test + void parseHeaderLineReturnsNullForMissingColon() { + byte[] buf = "invalid header line".getBytes(StandardCharsets.US_ASCII); + var headers = HttpHeaders.ofModifiable(); + String result = H1Utils.parseHeaderLine(buf, buf.length, headers); + + assertNull(result); + } + + @Test + void parseHeaderLineReturnsNullForColonAtStart() { + byte[] buf = ": value".getBytes(StandardCharsets.US_ASCII); + var headers = HttpHeaders.ofModifiable(); + String result = H1Utils.parseHeaderLine(buf, buf.length, headers); + + assertNull(result); + } + + @Test + void parseHeaderLineTrimsWhitespace() { + byte[] buf = "name: value ".getBytes(StandardCharsets.US_ASCII); + var headers = HttpHeaders.ofModifiable(); + H1Utils.parseHeaderLine(buf, buf.length, headers); + + assertEquals("value", headers.firstValue("name")); + } + + @Test + void parseHeaderLineTrimsTab() { + byte[] buf = "name:\t\tvalue\t".getBytes(StandardCharsets.US_ASCII); + var headers = HttpHeaders.ofModifiable(); + H1Utils.parseHeaderLine(buf, buf.length, headers); + + assertEquals("value", headers.firstValue("name")); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStreamTest.java new file mode 100644 index 0000000000..05131ce689 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/NonClosingOutputStreamTest.java @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +class NonClosingOutputStreamTest { + + @Test + void doesNotCloseDelegate() throws IOException { + var delegateClosed = new AtomicInteger(0); + var delegate = new ByteArrayOutputStream() { + @Override + public void close() { + delegateClosed.incrementAndGet(); + } + }; + + var stream = new NonClosingOutputStream(delegate); + stream.write(new byte[] {1, 2, 3}); + stream.close(); + + assertEquals(0, delegateClosed.get()); + assertArrayEquals(new byte[] {1, 2, 3}, delegate.toByteArray()); + } + + @Test + void flushesOnClose() throws IOException { + var flushCount = new AtomicInteger(0); + var delegate = new ByteArrayOutputStream() { + @Override + public void flush() { + flushCount.incrementAndGet(); + } + }; + + var stream = new NonClosingOutputStream(delegate); + stream.close(); + + assertTrue(flushCount.get() >= 1); + } + + @Test + void throwsAfterClose() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new NonClosingOutputStream(delegate); + stream.close(); + + assertThrows(IOException.class, () -> stream.write(1)); + assertThrows(IOException.class, () -> stream.write(new byte[] {1, 2, 3}, 0, 3)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStreamTest.java new file mode 100644 index 0000000000..2801663962 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedInputStreamTest.java @@ -0,0 +1,661 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class UnsyncBufferedInputStreamTest { + + @Test + void readsSingleBytes() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(1, stream.read()); + assertEquals(2, stream.read()); + assertEquals(3, stream.read()); + assertEquals(-1, stream.read()); + } + + @Test + void readsIntoArray() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + byte[] buf = new byte[3]; + assertEquals(3, stream.read(buf)); + assertArrayEquals(new byte[] {1, 2, 3}, buf); + } + + @Test + void readArrayDelegatesToReadWithOffsetAndLength() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + byte[] buf = new byte[5]; + assertEquals(3, stream.read(buf)); + assertArrayEquals(new byte[] {1, 2, 3, 0, 0}, buf); + } + + @Test + void readWithOffsetAndLength() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + byte[] buf = new byte[10]; + assertEquals(3, stream.read(buf, 2, 3)); + assertArrayEquals(new byte[] {0, 0, 1, 2, 3, 0, 0, 0, 0, 0}, buf); + } + + @Test + void readReturnsZeroWhenLenIsZero() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(0, stream.read(new byte[10], 0, 0)); + } + + @Test + void readThrowsOnNegativeOffset() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[10], -1, 5)); + } + + @Test + void readThrowsOnNegativeLength() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[10], 0, -1)); + } + + @Test + void readThrowsWhenLengthExceedsArrayBounds() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[10], 5, 10)); + } + + @Test + void readBypassesBufferForLargeRequests() throws IOException { + var data = new byte[100]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) i; + } + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + byte[] buf = new byte[100]; + assertEquals(100, stream.read(buf)); + assertArrayEquals(data, buf); + } + + @Test + void readDrainsBufferThenRefills() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + // First read fills buffer with [1,2,3,4], returns 3 + byte[] buf = new byte[3]; + assertEquals(3, stream.read(buf)); + assertArrayEquals(new byte[] {1, 2, 3}, buf); + + // Second read drains remaining [4], refills with [5,6,7,8], returns 3 + assertEquals(3, stream.read(buf)); + assertArrayEquals(new byte[] {4, 5, 6}, buf); + } + + @Test + void readReturnsMinusOneOnEmptyStream() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(-1, stream.read()); + assertEquals(-1, stream.read(new byte[10])); + } + + @Test + void readReturnsPartialDataThenMinusOne() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + byte[] buf = new byte[10]; + assertEquals(2, stream.read(buf)); + assertEquals(-1, stream.read(buf)); + } + + @Test + void readThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.read(new byte[10], 0, 5)); + } + + @Test + void skipsBytes() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(2, stream.skip(2)); + assertEquals(3, stream.read()); + } + + @Test + void skipReturnsZeroForNonPositive() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(0, stream.skip(0)); + assertEquals(0, stream.skip(-5)); + } + + @Test + void skipThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.skip(1)); + } + + @Test + void skipDrainsBufferThenSkipsUnderlying() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + // Fill buffer first + stream.read(); + + // Skip more than buffer has (3 in buffer + some from underlying) + assertEquals(6, stream.skip(6)); + assertEquals(8, stream.read()); + } + + @Test + void availableReturnsBufferedPlusUnderlying() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Before any read, buffer is empty + assertEquals(5, stream.available()); + + // After read, buffer has data + stream.read(); + assertEquals(4, stream.available()); + } + + @Test + void availableThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, stream::available); + } + + @Test + void closeIsIdempotent() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + stream.close(); + stream.close(); // Should not throw + } + + @Test + void transfersToOutputStream() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + var out = new ByteArrayOutputStream(); + + assertEquals(5, stream.transferTo(out)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5}, out.toByteArray()); + } + + @Test + void transferToDrainsBufferFirst() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Read one byte to fill buffer + assertEquals(1, stream.read()); + + var out = new ByteArrayOutputStream(); + assertEquals(4, stream.transferTo(out)); + assertArrayEquals(new byte[] {2, 3, 4, 5}, out.toByteArray()); + } + + @Test + void transferToThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.transferTo(new ByteArrayOutputStream())); + } + + @Test + void discardConsumesBufferedAndUnderlyingBytes() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + assertEquals(1, stream.read()); + stream.discard(5); + + assertEquals(7, stream.read()); + assertEquals(8, stream.read()); + assertEquals(-1, stream.read()); + } + + @Test + void discardPreservesBufferedBytesAfterDiscardedRange() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + assertEquals(1, stream.read()); + stream.discard(1); + + assertEquals(3, stream.read()); + assertEquals(4, stream.read()); + assertEquals(5, stream.read()); + assertEquals(-1, stream.read()); + } + + @Test + void discardThrowsOnPrematureEof() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + assertThrows(IOException.class, () -> stream.discard(4)); + } + + @Test + void discardThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + stream.close(); + + assertThrows(IOException.class, () -> stream.discard(1)); + } + + @Test + void readLineReturnsLine() throws IOException { + var data = "Hello\r\nWorld\n".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + byte[] buf = new byte[64]; + int len = stream.readLine(buf, 64); + assertEquals(5, len); + assertEquals("Hello", new String(buf, 0, len, StandardCharsets.US_ASCII)); + + len = stream.readLine(buf, 64); + assertEquals(5, len); + assertEquals("World", new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + @Test + void readLineHandlesCrOnly() throws IOException { + var data = "Hello\rWorld".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + byte[] buf = new byte[64]; + int len = stream.readLine(buf, 64); + assertEquals(5, len); + assertEquals("Hello", new String(buf, 0, len, StandardCharsets.US_ASCII)); + + len = stream.readLine(buf, 64); + assertEquals(5, len); + assertEquals("World", new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + @Test + void readLineReturnsMinusOneOnEmptyStream() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {}); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + assertEquals(-1, stream.readLine(new byte[64], 64)); + } + + @Test + void readLineReturnsDataWithoutTerminatorAtEof() throws IOException { + var data = "Hello".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + byte[] buf = new byte[64]; + int len = stream.readLine(buf, 64); + assertEquals("Hello", new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + @Test + void readLineThrowsWhenExceedsMaxLength() throws IOException { + var data = "HelloWorld\r\n".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + assertThrows(IOException.class, () -> stream.readLine(new byte[64], 5)); + } + + @Test + void readLineThrowsWhenExceedsBufferSize() throws IOException { + var data = "HelloWorld\r\n".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + assertThrows(IOException.class, () -> stream.readLine(new byte[5], 64)); + } + + @Test + void readLineThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream("Hello\r\n".getBytes(StandardCharsets.US_ASCII)); + var stream = new UnsyncBufferedInputStream(delegate, 64); + stream.close(); + + assertThrows(IOException.class, () -> stream.readLine(new byte[64], 64)); + } + + @Test + void readLineHandlesEmptyLine() throws IOException { + var data = "\r\nHello\r\n".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + byte[] buf = new byte[64]; + int len = stream.readLine(buf, 64); + assertEquals(0, len); + + len = stream.readLine(buf, 64); + assertEquals("Hello", new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + @Test + void readLineSpansMultipleBufferFills() throws IOException { + var data = "HelloWorld\r\n".getBytes(StandardCharsets.US_ASCII); + var delegate = new ByteArrayInputStream(data); + var stream = new UnsyncBufferedInputStream(delegate, 4); // Small buffer + + byte[] buf = new byte[64]; + int len = stream.readLine(buf, 64); + assertEquals("HelloWorld", new String(buf, 0, len, StandardCharsets.US_ASCII)); + } + + @Test + void throwsAfterClose() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, stream::read); + } + + @Test + void throwsOnInvalidBufferSize() { + var delegate = new ByteArrayInputStream(new byte[] {}); + assertThrows(IllegalArgumentException.class, + () -> new UnsyncBufferedInputStream(delegate, 0)); + } + + @Test + void throwsOnNegativeBufferSize() { + var delegate = new ByteArrayInputStream(new byte[] {}); + assertThrows(IllegalArgumentException.class, + () -> new UnsyncBufferedInputStream(delegate, -1)); + } + + // ==================== Direct Buffer Access Tests ==================== + + @Test + void bufferReturnsInternalBuffer() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Trigger a read to fill the buffer + stream.read(); + + byte[] buf = stream.buffer(); + assertEquals(8, buf.length); // Buffer size we specified + } + + @Test + void positionAndLimitTrackBufferState() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Initially empty + assertEquals(0, stream.position()); + assertEquals(0, stream.limit()); + assertEquals(0, stream.buffered()); + + // After read, buffer is filled + stream.read(); + assertEquals(1, stream.position()); // Advanced by one read + assertEquals(5, stream.limit()); // All 5 bytes loaded + assertEquals(4, stream.buffered()); // 4 remaining + } + + @Test + void consumeAdvancesPosition() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Fill buffer + stream.read(); + int initialPos = stream.position(); + + stream.consume(2); + assertEquals(initialPos + 2, stream.position()); + assertEquals(2, stream.buffered()); + } + + @Test + void consumeThrowsOnOverflow() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Fill buffer + stream.read(); + + assertThrows(IndexOutOfBoundsException.class, () -> stream.consume(10)); + } + + @Test + void consumeThrowsOnNegative() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + stream.read(); + + assertThrows(IndexOutOfBoundsException.class, () -> stream.consume(-1)); + } + + @Test + void ensureReturnsTrueWhenDataAvailable() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(true, stream.ensure(5)); + // ensure() reads at least 5 bytes, may read more (up to buffer size) + assertEquals(true, stream.buffered() >= 5); + } + + @Test + void ensureCompactsAndFillsBuffer() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Fill buffer and consume some + stream.ensure(8); // Fill entire buffer [1,2,3,4,5,6,7,8] + stream.consume(6); // Now position=6, only 2 bytes left [7,8] + + // Ensure more than available - should compact and fill + assertEquals(true, stream.ensure(4)); + // After compacting, position should be 0 + assertEquals(0, stream.position()); + assertEquals(true, stream.buffered() >= 4); + + // Verify data integrity - after consuming bytes 1-6, next byte should be 7 + byte[] buf = stream.buffer(); + assertEquals(7, buf[0]); // First unread byte after consuming 1-6 + } + + @Test + void ensureReturnsFalseOnEof() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Try to ensure more bytes than available (but within buffer size) + assertEquals(false, stream.ensure(5)); + // But we should have whatever was available + assertEquals(3, stream.buffered()); + } + + @Test + void ensureThrowsWhenRequestExceedsBufferSize() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + assertThrows(IllegalArgumentException.class, () -> stream.ensure(10)); + } + + @Test + void ensureReturnsTrueForZeroOrNegative() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + assertEquals(true, stream.ensure(0)); + assertEquals(true, stream.ensure(-5)); + } + + @Test + void ensureThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.ensure(1)); + } + + @Test + void readDirectBypassesBuffer() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Buffer is empty initially, so readDirect should work + byte[] buf = new byte[3]; + int n = stream.readDirect(buf, 0, 3); + assertEquals(3, n); + assertArrayEquals(new byte[] {1, 2, 3}, buf); + } + + @Test + void readDirectThrowsIfBufferNotEmpty() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + + // Fill the buffer by reading one byte + stream.read(); + + // Now buffer has data, readDirect should throw + assertThrows(IllegalStateException.class, () -> stream.readDirect(new byte[3], 0, 3)); + } + + @Test + void readDirectWorksAfterDrainingBuffer() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); + var stream = new UnsyncBufferedInputStream(delegate, 4); + + // Fill buffer [1,2,3,4] and consume all + stream.ensure(4); + stream.consume(4); + + // Buffer is now empty, readDirect should work + byte[] buf = new byte[4]; + int n = stream.readDirect(buf, 0, 4); + assertEquals(4, n); + assertArrayEquals(new byte[] {5, 6, 7, 8}, buf); + } + + @Test + void readDirectThrowsWhenClosed() throws IOException { + var delegate = new ByteArrayInputStream(new byte[] {1, 2, 3}); + var stream = new UnsyncBufferedInputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.readDirect(new byte[3], 0, 3)); + } + + @Test + void directBufferAccessForZeroCopyParsing() throws IOException { + // Simulate zero-copy frame header parsing like H2FrameCodec does + byte[] frameData = { + 0, + 0, + 10, // length = 10 + 0, // type = DATA + 1, // flags = END_STREAM + 0, + 0, + 0, + 1, // stream ID = 1 + 'H', + 'e', + 'l', + 'l', + 'o', + ' ', + 'W', + 'o', + 'r', + 'l' // payload + }; + var delegate = new ByteArrayInputStream(frameData); + var stream = new UnsyncBufferedInputStream(delegate, 64); + + // Ensure 9-byte header is available + assertEquals(true, stream.ensure(9)); + + // Parse header directly from buffer (zero-copy) + byte[] buf = stream.buffer(); + int p = stream.position(); + + int length = ((buf[p] & 0xFF) << 16) + | ((buf[p + 1] & 0xFF) << 8) + | (buf[p + 2] & 0xFF); + int type = buf[p + 3] & 0xFF; + int flags = buf[p + 4] & 0xFF; + int streamId = ((buf[p + 5] & 0x7F) << 24) + | ((buf[p + 6] & 0xFF) << 16) + | ((buf[p + 7] & 0xFF) << 8) + | (buf[p + 8] & 0xFF); + + stream.consume(9); + + assertEquals(10, length); + assertEquals(0, type); + assertEquals(1, flags); + assertEquals(1, streamId); + + // Now read the payload + byte[] payload = new byte[length]; + assertEquals(length, stream.read(payload)); + assertEquals("Hello Worl", new String(payload, StandardCharsets.US_ASCII)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStreamTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStreamTest.java new file mode 100644 index 0000000000..83764f0932 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h1/UnsyncBufferedOutputStreamTest.java @@ -0,0 +1,138 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h1; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class UnsyncBufferedOutputStreamTest { + + @Test + void writesSingleBytes() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + + stream.write(1); + stream.write(2); + stream.write(3); + stream.flush(); + + assertArrayEquals(new byte[] {1, 2, 3}, delegate.toByteArray()); + } + + @Test + void singleByteWriteFlushesWhenBufferFull() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 4); + + stream.write(1); + stream.write(2); + stream.write(3); + stream.write(4); + // Buffer is now full, next write should flush + stream.write(5); + stream.flush(); + + assertArrayEquals(new byte[] {1, 2, 3, 4, 5}, delegate.toByteArray()); + } + + @Test + void zeroLengthWriteDoesNothing() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + + stream.write(new byte[] {1, 2, 3}, 0, 0); + stream.flush(); + + assertEquals(0, delegate.size()); + } + + @Test + void writesArray() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + + stream.write(new byte[] {1, 2, 3, 4, 5}); + stream.flush(); + + assertArrayEquals(new byte[] {1, 2, 3, 4, 5}, delegate.toByteArray()); + } + + @Test + void writesAsciiString() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + + stream.writeAscii("Hello"); + stream.flush(); + + assertEquals("Hello", delegate.toString()); + } + + @Test + void writeAsciiFlushesWhenBufferFills() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 4); + + // String longer than buffer forces mid-string flush + stream.writeAscii("HelloWorld"); + stream.flush(); + + assertEquals("HelloWorld", delegate.toString()); + } + + @Test + void flushesOnClose() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + + stream.write(new byte[] {1, 2, 3}); + stream.close(); + + assertArrayEquals(new byte[] {1, 2, 3}, delegate.toByteArray()); + } + + @Test + void throwsAfterClose() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, () -> stream.write(1)); + } + + @Test + void flushThrowsAfterClose() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 8); + stream.close(); + + assertThrows(IOException.class, stream::flush); + } + + @Test + void throwsOnInvalidBufferSize() { + var delegate = new ByteArrayOutputStream(); + assertThrows(IllegalArgumentException.class, + () -> new UnsyncBufferedOutputStream(delegate, 0)); + } + + @Test + void largeWriteBypassesBuffer() throws IOException { + var delegate = new ByteArrayOutputStream(); + var stream = new UnsyncBufferedOutputStream(delegate, 4); + + stream.write(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); + stream.flush(); + + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, delegate.toByteArray()); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ByteAllocatorTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ByteAllocatorTest.java new file mode 100644 index 0000000000..e98b5d29dc --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ByteAllocatorTest.java @@ -0,0 +1,237 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +class ByteAllocatorTest { + + @Test + void borrowReturnsBufferOfRequestedSize() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + ByteBuffer buffer = pool.borrow(256); + + assertNotNull(buffer); + assertTrue(buffer.capacity() >= 256); + } + + @Test + void borrowReturnsDefaultSizeWhenRequestedSizeIsSmaller() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + ByteBuffer buffer = pool.borrow(64); + + assertNotNull(buffer); + assertEquals(128, buffer.capacity()); + } + + @Test + void releasedBufferCanBeReused() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + ByteBuffer buffer1 = pool.borrow(128); + pool.release(buffer1); + ByteBuffer buffer2 = pool.borrow(128); + + assertSame(buffer1, buffer2, "Should reuse the same buffer"); + } + + @Test + void poolSizeIncreasesOnRelease() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + assertEquals(0, pool.size()); + + ByteBuffer buffer = pool.borrow(128); + pool.release(buffer); + + assertEquals(1, pool.size()); + } + + @Test + void poolSizeDecreasesOnBorrow() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + ByteBuffer buffer1 = pool.borrow(128); + pool.release(buffer1); + assertEquals(1, pool.size()); + + pool.borrow(128); + assertEquals(0, pool.size()); + } + + @Test + void poolRespectsMaxSize() { + ByteAllocator pool = new ByteAllocator(2, 128, 128, 128); + + pool.release(ByteBuffer.allocate(128)); + pool.release(ByteBuffer.allocate(128)); + assertEquals(2, pool.size()); + + pool.release(ByteBuffer.allocate(128)); + assertEquals(2, pool.size()); + } + + @Test + void buffersLargerThanMaxPoolableSizeAreNotPooled() { + ByteAllocator pool = new ByteAllocator(10, 1024, 256, 128); + + ByteBuffer largeBuffer = ByteBuffer.allocate(512); + pool.release(largeBuffer); + + assertEquals(0, pool.size()); + } + + @Test + void borrowThrowsWhenRequestedSizeExceedsMaxBufferSize() { + ByteAllocator pool = new ByteAllocator(10, 256, 256, 128); + + assertThrows(IllegalArgumentException.class, () -> pool.borrow(512)); + } + + @Test + void nullBufferIsIgnored() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + pool.release(null); + + assertEquals(0, pool.size()); + } + + @Test + void clearRemovesAllBuffers() { + ByteAllocator pool = new ByteAllocator(10, 128, 128, 128); + + pool.release(ByteBuffer.allocate(128)); + pool.release(ByteBuffer.allocate(128)); + pool.release(ByteBuffer.allocate(128)); + assertEquals(3, pool.size()); + + pool.clear(); + + assertEquals(0, pool.size()); + } + + @Test + void tooSmallPooledBufferIsDropped() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + ByteBuffer smallBuffer = ByteBuffer.allocate(64); + pool.release(smallBuffer); + assertEquals(0, pool.size()); + + ByteBuffer buffer = pool.borrow(256); + assertEquals(0, pool.size()); + assertTrue(buffer.capacity() >= 256); + assertNotSame(smallBuffer, buffer); + } + + @Test + void constructorValidatesMaxPoolCount() { + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(0, 1024, 1024, 128)); + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(-1, 1024, 1024, 128)); + } + + @Test + void constructorValidatesDefaultBufferSize() { + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(10, 1024, 1024, 0)); + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(10, 1024, 1024, -1)); + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(10, 1024, 256, 512)); + } + + @Test + void constructorValidatesMaxPoolableSize() { + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(10, 1024, 0, 128)); + assertThrows(IllegalArgumentException.class, () -> new ByteAllocator(10, 256, 512, 128)); + } + + @Test + void borrowThrowsWhenMinSizeIsZeroOrNegative() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + + assertThrows(IllegalArgumentException.class, () -> pool.borrow(0)); + assertThrows(IllegalArgumentException.class, () -> pool.borrow(-1)); + } + + @Test + void lifoOrderPreserved() { + ByteAllocator pool = new ByteAllocator(10, 128, 128, 128); + + ByteBuffer buffer1 = ByteBuffer.allocate(128); + ByteBuffer buffer2 = ByteBuffer.allocate(128); + ByteBuffer buffer3 = ByteBuffer.allocate(128); + + pool.release(buffer1); + pool.release(buffer2); + pool.release(buffer3); + + assertSame(buffer3, pool.borrow(128)); + assertSame(buffer2, pool.borrow(128)); + assertSame(buffer1, pool.borrow(128)); + } + + @Test + void largerSizeClassCanSatisfySmallerBorrow() { + ByteAllocator pool = new ByteAllocator(10, 1024, 1024, 128); + ByteBuffer larger = ByteBuffer.allocateDirect(512); + + pool.release(larger); + + ByteBuffer borrowed = pool.borrow(256); + assertTrue(borrowed.capacity() >= 256); + assertEquals(0, pool.size()); + } + + @Test + void concurrentBorrowAndReleaseIsThreadSafe() throws InterruptedException { + ByteAllocator pool = new ByteAllocator(100, 1024, 1024, 128); + int threadCount = 10; + int operationsPerThread = 1000; + + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + CountDownLatch latch = new CountDownLatch(threadCount); + List errors = new ArrayList<>(); + + for (int t = 0; t < threadCount; t++) { + executor.submit(() -> { + try { + for (int i = 0; i < operationsPerThread; i++) { + ByteBuffer buffer = pool.borrow(128); + assertNotNull(buffer); + buffer.put(0, (byte) i); + pool.release(buffer); + } + } catch (Throwable e) { + synchronized (errors) { + errors.add(e); + } + } finally { + latch.countDown(); + } + }); + } + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + executor.shutdown(); + + assertTrue(errors.isEmpty(), "Concurrent operations should not throw: " + errors); + assertTrue(pool.size() <= 100); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReaderTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReaderTest.java new file mode 100644 index 0000000000..865313df5b --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/ChannelFrameReaderTest.java @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.nio.channels.Channels; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.jupiter.api.Test; + +class ChannelFrameReaderTest { + + @Test + void hasBufferedDataIncludesTransportBufferedPlaintext() { + AtomicBoolean transportBuffered = new AtomicBoolean(false); + ChannelFrameReader reader = new ChannelFrameReader( + Channels.newChannel(new ByteArrayInputStream(new byte[0])), + 8, + transportBuffered::get); + + assertFalse(reader.hasBufferedData()); + + transportBuffered.set(true); + + assertTrue(reader.hasBufferedData()); + } + + @Test + void hasBufferedDataIncludesReaderBuffer() throws Exception { + ChannelFrameReader reader = new ChannelFrameReader( + Channels.newChannel(new ByteArrayInputStream(new byte[] {1})), + 8); + + reader.ensure(1); + + assertTrue(reader.hasBufferedData()); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/DynamicTableTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/DynamicTableTest.java new file mode 100644 index 0000000000..1eb2b9f87f --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/DynamicTableTest.java @@ -0,0 +1,173 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class DynamicTableTest { + + @Test + void addsEntry() { + var table = new DynamicTable(4096); + + table.add("name", "value"); + + assertEquals(1, table.length()); + assertEquals("name", table.getName(62)); + assertEquals("value", table.getValue(62)); + } + + @Test + void calculatesEntrySize() { + // name(4) + value(5) + 32 overhead = 41 + int size = DynamicTable.entrySize("name", "value"); + + assertEquals(41, size); + } + + @Test + void tracksTotalSize() { + var table = new DynamicTable(4096); + + table.add("name", "value"); // 4 + 5 + 32 = 41 + + assertEquals(41, table.size()); + } + + @Test + void evictsOldestWhenFull() { + // Table size 100, each entry ~41 bytes, so fits 2 entries + var table = new DynamicTable(100); + + table.add("first", "value"); // 5 + 5 + 32 = 42 + table.add("second", "value"); // 6 + 5 + 32 = 43 + // Total = 85, fits + assertEquals(2, table.length()); + + table.add("third", "value"); // 5 + 5 + 32 = 42 + // Would be 127, exceeds 100, so evict oldest + + assertEquals(2, table.length()); + assertEquals("third", table.getName(62)); + assertEquals("second", table.getName(63)); + } + + @Test + void clearsWhenEntryTooLarge() { + var table = new DynamicTable(50); + table.add("a", "b"); // 1 + 1 + 32 = 34 + + // Entry larger than max table size + table.add("verylongname", "verylongvalue"); // 12 + 13 + 32 = 57 > 50 + + assertEquals(0, table.length()); + assertEquals(0, table.size()); + } + + @Test + void setMaxSizeEvicts() { + var table = new DynamicTable(4096); + table.add("name1", "value1"); // 5 + 6 + 32 = 43 + table.add("name2", "value2"); // 5 + 6 + 32 = 43 + assertEquals(2, table.length()); + + table.setMaxSize(50); // Only room for 1 entry + + assertEquals(1, table.length()); + assertEquals("name2", table.getName(62)); + } + + @Test + void setMaxSizeToZeroClears() { + var table = new DynamicTable(4096); + table.add("name", "value"); + + table.setMaxSize(0); + + assertEquals(0, table.length()); + } + + @Test + void getThrowsOnInvalidIndex() { + var table = new DynamicTable(4096); + table.add("name", "value"); + + assertThrows(IndexOutOfBoundsException.class, () -> table.getName(61)); // Below dynamic range + assertThrows(IndexOutOfBoundsException.class, () -> table.getName(63)); // Only 1 entry at 62 + } + + @Test + void findFullMatchReturnsIndex() { + var table = new DynamicTable(4096); + table.add("first", "value1"); + table.add("second", "value2"); + + int index = table.findFullMatch("first", "value1"); + + assertEquals(63, index); // second entry (first is at 62) + } + + @Test + void findFullMatchReturnsNegativeWhenNotFound() { + var table = new DynamicTable(4096); + table.add("name", "value"); + + assertEquals(-1, table.findFullMatch("name", "other")); + assertEquals(-1, table.findFullMatch("other", "value")); + } + + @Test + void findNameMatchReturnsIndex() { + var table = new DynamicTable(4096); + table.add("first", "value1"); + table.add("second", "value2"); + + int index = table.findNameMatch("first"); + + assertEquals(63, index); + } + + @Test + void findNameMatchReturnsNegativeWhenNotFound() { + var table = new DynamicTable(4096); + table.add("name", "value"); + + assertEquals(-1, table.findNameMatch("other")); + } + + @Test + void clearRemovesAllEntries() { + var table = new DynamicTable(4096); + table.add("name1", "value1"); + table.add("name2", "value2"); + + table.clear(); + + assertEquals(0, table.length()); + assertEquals(0, table.size()); + } + + @Test + void maxSizeReturnsConfiguredMax() { + var table = new DynamicTable(1234); + + assertEquals(1234, table.maxSize()); + } + + @Test + void indicesShiftOnAdd() { + var table = new DynamicTable(4096); + table.add("first", "v"); + assertEquals(62, table.findFullMatch("first", "v")); + + table.add("second", "v"); + assertEquals(62, table.findFullMatch("second", "v")); + assertEquals(63, table.findFullMatch("first", "v")); // shifted + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/FlowControlWindowTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/FlowControlWindowTest.java new file mode 100644 index 0000000000..170d9e6cda --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/FlowControlWindowTest.java @@ -0,0 +1,157 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class FlowControlWindowTest { + + @Test + void initialWindowIsAvailable() { + var window = new FlowControlWindow(65535); + assertEquals(65535, window.available()); + } + + @Test + void tryAcquireNonBlockingReducesWindow() { + var window = new FlowControlWindow(1000); + int acquired = window.tryAcquireNonBlocking(400); + + assertEquals(400, acquired); + assertEquals(600, window.available()); + } + + @Test + void tryAcquireNonBlockingReturnsZeroWhenEmpty() { + var window = new FlowControlWindow(0); + int acquired = window.tryAcquireNonBlocking(200); + + assertEquals(0, acquired); + } + + @Test + void tryAcquireNonBlockingAcquiresPartial() { + var window = new FlowControlWindow(100); + int acquired = window.tryAcquireNonBlocking(200); + + assertEquals(100, acquired); + assertEquals(0, window.available()); + } + + @Test + void releaseIncreasesWindow() { + var window = new FlowControlWindow(1000); + window.release(500); + + assertEquals(1500, window.available()); + } + + @Test + void adjustIncreasesWindow() { + var window = new FlowControlWindow(1000); + window.adjust(500); + + assertEquals(1500, window.available()); + } + + @Test + void adjustDecreasesWindow() { + var window = new FlowControlWindow(1000); + window.adjust(-300); + + assertEquals(700, window.available()); + } + + @Test + void adjustCanMakeWindowNegative() { + var window = new FlowControlWindow(100); + window.adjust(-200); + + assertEquals(-100, window.available()); + } + + @Test + void concurrentAcquireAndRelease() throws Exception { + var window = new FlowControlWindow(1000); + int threads = 10; + int iterations = 100; + + Thread[] workers = new Thread[threads]; + for (int i = 0; i < threads; i++) { + workers[i] = Thread.startVirtualThread(() -> { + for (int j = 0; j < iterations; j++) { + window.tryAcquireNonBlocking(10); + window.release(10); + } + }); + } + + for (Thread t : workers) { + t.join(5000); + } + + assertEquals(1000, window.available(), "Window should be back to initial"); + } + + @Nested + class BlockingAcquireTest { + + @Test + void tryAcquireUpToReturnsImmediatelyWhenWindowAvailable() throws InterruptedException { + var window = new FlowControlWindow(1000); + int acquired = window.tryAcquireUpTo(500, 1000); + + assertEquals(500, acquired); + assertEquals(500, window.available()); + } + + @Test + void tryAcquireUpToReturnsPartialWhenWindowSmaller() throws InterruptedException { + var window = new FlowControlWindow(100); + int acquired = window.tryAcquireUpTo(500, 1000); + + assertEquals(100, acquired); + assertEquals(0, window.available()); + } + + @Test + void tryAcquireUpToTimesOutWhenWindowEmpty() throws InterruptedException { + var window = new FlowControlWindow(0); + long start = System.nanoTime(); + int acquired = window.tryAcquireUpTo(100, 50); + long elapsed = (System.nanoTime() - start) / 1_000_000; + + assertEquals(0, acquired); + assertTrue(elapsed >= 40, "Should have waited ~50ms, waited " + elapsed + "ms"); + } + + @Test + void tryAcquireUpToWakesOnRelease() throws InterruptedException { + var window = new FlowControlWindow(0); + + Thread releaser = Thread.startVirtualThread(() -> { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + window.release(200); + }); + + long start = System.nanoTime(); + int acquired = window.tryAcquireUpTo(100, 5000); + long elapsed = (System.nanoTime() - start) / 1_000_000; + + assertEquals(100, acquired); + assertTrue(elapsed < 2000, "Should have woken up quickly after release, took " + elapsed + "ms"); + releaser.join(1000); + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecFuzzTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecFuzzTest.java new file mode 100644 index 0000000000..50afc13420 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecFuzzTest.java @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import com.code_intelligence.jazzer.junit.FuzzTest; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; + +/** + * Fuzz test for H2 frame codec — feeds random bytes as a stream of H2 frames. + */ +class H2FrameCodecFuzzTest { + + private static final int MAX_FUZZ_INPUT = 512; + + @FuzzTest + void fuzzFrameStream(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + var codec = new H2FrameCodec( + new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(data)), 1024), + new ChannelFrameWriter(Channels.newChannel(new ByteArrayOutputStream()), 1024), + 16384); + for (int i = 0; i < 10; i++) { + try { + codec.nextFrame(); + int length = codec.framePayloadLength(); + if (length > 0) { + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + } + } catch (IOException ignored) { + break; + } + } + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecTest.java new file mode 100644 index 0000000000..c052a806ec --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameCodecTest.java @@ -0,0 +1,609 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class H2FrameCodecTest { + + // Test helper record that simulates the old Frame record for testing + record TestFrame(int type, int flags, int streamId, byte[] payload, int length, H2FrameCodec codec) { + boolean hasFlag(int flag) { + return (flags & flag) != 0; + } + + int payloadLength() { + return length; + } + + int[] parseSettings() throws H2Exception { + return codec.parseSettings(payload, length); + } + + int[] parseGoaway() throws H2Exception { + return codec.parseGoaway(payload, length); + } + + int parseWindowUpdate() throws H2Exception { + return codec.parseWindowUpdate(payload, length); + } + + int parseRstStream() throws H2Exception { + return codec.parseRstStream(payload, length); + } + } + + // Write helper methods + @Test + void writeSettings() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeSettings(1, 4096, 3, 100); + c.flush(); + var frame = decode(out); + int[] s = frame.parseSettings(); + + assertEquals(4, s.length); + assertEquals(1, s[0]); + assertEquals(4096, s[1]); + assertEquals(3, s[2]); + assertEquals(100, s[3]); + } + + @Test + void writeSettingsAck() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeSettingsAck(); + c.flush(); + var frame = decode(out); + + assertEquals(4, frame.type()); + assertEquals(1, frame.flags()); + assertEquals(0, frame.payloadLength()); + assertEquals(0, frame.streamId()); + } + + @Test + void writeGoaway() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeGoaway(5, 2, "debug"); + c.flush(); + var frame = decode(out); + int[] g = frame.parseGoaway(); + + assertEquals(5, g[0]); + assertEquals(2, g[1]); + } + + @Test + void writeGoawayNullDebug() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeGoaway(1, 0, null); + c.flush(); + var frame = decode(out); + + assertEquals(7, frame.type()); + assertEquals(0, frame.streamId()); + assertEquals(8, frame.payloadLength()); + } + + @Test + void writeWindowUpdate() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeWindowUpdate(1, 65535); + c.flush(); + var frame = decode(out); + + assertEquals(65535, frame.parseWindowUpdate()); + } + + @Test + void writeRstStream() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeRstStream(1, 8); + c.flush(); + var frame = decode(out); + + assertEquals(8, frame.parseRstStream()); + } + + @Test + void writeHeadersWithContinuation() throws IOException { + var out = new ByteArrayOutputStream(); + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(out), 16); + byte[] block = new byte[50]; + codec.writeHeaders(1, block, 0, 50, true); + codec.flush(); + + var readCodec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + int type = readCodec.nextFrame(); + assertEquals(1, type); // HEADERS + int streamId = readCodec.frameStreamId(); + int length = readCodec.framePayloadLength(); + byte[] payload = new byte[length]; + readCodec.readPayloadInto(payload, 0, length); + readCodec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + + // Zero-copy: use headerBlockSize() for valid length + assertEquals(50, readCodec.headerBlockSize()); + } + + @Test + void writeHeadersSingleFrame() throws IOException { + var out = new ByteArrayOutputStream(); + var c = codec(out); + c.writeHeaders(1, new byte[] {1, 2, 3}, 0, 3, false); + c.flush(); + var frame = decode(out); + + assertTrue(frame.hasFlag(0x04)); // END_HEADERS + } + + // Validation + @Test + void throwsOnNegativeStreamId() { + assertThrows(IllegalArgumentException.class, + () -> codec(new ByteArrayOutputStream()).writeFrame(0, 0, -1, new byte[0])); + } + + // Note: We no longer validate outbound frame size in writeFrame() because + // the peer's MAX_FRAME_SIZE setting may be larger than our receive limit. + // The caller (H2Exchange.writeData) is responsible for chunking according + // to the peer's advertised MAX_FRAME_SIZE. + + @Test + void throwsOnWindowUpdateZero() { + assertThrows(IllegalArgumentException.class, () -> codec(new ByteArrayOutputStream()).writeWindowUpdate(1, 0)); + } + + @Test + void throwsOnOddSettingsCount() { + assertThrows(IllegalArgumentException.class, () -> codec(new ByteArrayOutputStream()).writeSettings(1, 2, 3)); + } + + // readHeaderBlock + @Test + void readHeaderBlockWithContinuation() throws IOException { + var out = new ByteArrayOutputStream(); + out.write(buildFrame(1, 0, 1, new byte[] {1, 2})); // HEADERS no END_HEADERS + out.write(buildFrame(9, 0x04, 1, new byte[] {3, 4})); // CONTINUATION with END_HEADERS + + var codec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + int type = codec.nextFrame(); + assertEquals(1, type); // HEADERS + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + byte[] block = codec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + int blockSize = codec.headerBlockSize(); + + // Zero-copy: block is a view into internal buffer, use headerBlockSize() for valid length + assertArrayEquals(new byte[] {1, 2, 3, 4}, Arrays.copyOf(block, blockSize)); + } + + @Test + void throwsOnContinuationWrongStream() throws IOException { + var out = new ByteArrayOutputStream(); + out.write(buildFrame(1, 0, 1, new byte[] {1})); + out.write(buildFrame(9, 0x04, 2, new byte[] {2})); // wrong stream + var codec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> { + int type = codec.nextFrame(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + codec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + }); + } + + @Test + void throwsOnNonContinuationInterrupt() throws IOException { + var out = new ByteArrayOutputStream(); + out.write(buildFrame(1, 0, 1, new byte[] {1})); + out.write(buildFrame(0, 0, 1, new byte[] {2})); // DATA interrupts + var codec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> { + int type = codec.nextFrame(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + codec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + }); + } + + @Test + void throwsOnEofDuringContinuation() throws IOException { + var out = new ByteArrayOutputStream(); + out.write(buildFrame(1, 0, 1, new byte[] {1})); + var codec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(IOException.class, () -> { + int type = codec.nextFrame(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + codec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + }); + } + + @Test + void readHeaderBlockFromPushPromise() throws IOException { + byte[] framePayload = {0, 0, 0, 2, 'a', 'b'}; + var codec = new H2FrameCodec(wrapIn(buildFrame(5, 0x04, 1, framePayload)), + wrapOut(new ByteArrayOutputStream()), + 16384); + int type = codec.nextFrame(); + assertEquals(5, type); // PUSH_PROMISE + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + byte[] block = codec.readHeaderBlock(streamId, payload, length, H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + + assertArrayEquals(new byte[] {'a', 'b'}, block); + } + + // Regression: padding, priority, and PUSH_PROMISE prelude bytes must be stripped from the header + // block before HPACK sees them, on the single-frame (END_HEADERS) path too. + @Test + void headersStripsPadding() throws IOException { + // PADDED + END_HEADERS: [padLen=2][h1, h2][pad, pad] + byte[] block = readHeaderBlockWithCap( + buildFrame(1, H2Constants.FLAG_PADDED | H2Constants.FLAG_END_HEADERS, 1, new byte[] {2, 10, 20, 0, 0}), + H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + assertArrayEquals(new byte[] {10, 20}, block); + } + + @Test + void headersStripsPriorityBlock() throws IOException { + // PRIORITY + END_HEADERS: [5-byte priority block][h1, h2] + byte[] block = readHeaderBlockWithCap( + buildFrame(1, + H2Constants.FLAG_PRIORITY | H2Constants.FLAG_END_HEADERS, + 1, + new byte[] {0, 0, 0, 0, 5, 10, 20}), + H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + assertArrayEquals(new byte[] {10, 20}, block); + } + + @Test + void headersStripsPaddingAndPriority() throws IOException { + // PADDED + PRIORITY + END_HEADERS: [padLen=1][5-byte priority][h1, h2][pad] + byte[] block = readHeaderBlockWithCap( + buildFrame(1, + H2Constants.FLAG_PADDED | H2Constants.FLAG_PRIORITY | H2Constants.FLAG_END_HEADERS, + 1, + new byte[] {1, 0, 0, 0, 0, 5, 10, 20, 99}), + H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + assertArrayEquals(new byte[] {10, 20}, block); + } + + @Test + void pushPromiseStripsPaddingAndPromisedStreamId() throws IOException { + // PADDED + END_HEADERS: [padLen=1][4-byte promised stream id][h1, h2][pad] + byte[] block = readHeaderBlockWithCap( + buildFrame(5, + H2Constants.FLAG_PADDED | H2Constants.FLAG_END_HEADERS, + 1, + new byte[] {1, 0, 0, 0, 2, 10, 20, 99}), + H2Constants.DEFAULT_MAX_HEADER_LIST_SIZE); + assertArrayEquals(new byte[] {10, 20}, block); + } + + // Regression: the accumulated header block size cap is enforced as a running check, so an + // oversized block is rejected without first buffering all of it. + @Test + void singleFrameHeaderBlockExceedingCapThrows() { + assertThrows(H2Exception.class, + () -> readHeaderBlockWithCap( + buildFrame(1, H2Constants.FLAG_END_HEADERS, 1, new byte[20]), + 10)); + } + + @Test + void continuationHeaderBlockExceedingCapThrows() throws IOException { + var out = new ByteArrayOutputStream(); + out.write(buildFrame(1, 0, 1, new byte[8])); // HEADERS, no END_HEADERS + out.write(buildFrame(9, H2Constants.FLAG_END_HEADERS, 1, new byte[8])); // CONTINUATION, END_HEADERS + // 8 + 8 = 16 bytes accumulated, cap is 10 + assertThrows(H2Exception.class, () -> readHeaderBlockWithCap(out.toByteArray(), 10)); + } + + // Padding validation note: With the stateful API, padding processing is the caller's + // responsibility. The codec validates minimum payload size for PADDED flag but doesn't + // read/validate the actual pad length byte since that requires reading the payload. + // H2Connection.handleDataFrame() handles this validation when processing DATA frames. + + @Test + void throwsOnPriorityHeadersTooShort() { + assertThrows(H2Exception.class, () -> decodeAndReadPayload(buildFrame(1, 0x24, 1, new byte[3]))); + } + + // validateFrameSize tests + @Test + void throwsOnPingWrongSize() { + assertThrows(H2Exception.class, () -> decode(buildFrame(6, 0, 0, new byte[4]))); + } + + @Test + void throwsOnSettingsAckNonEmpty() { + assertThrows(H2Exception.class, () -> decode(buildFrame(4, 0x01, 0, new byte[6]))); + } + + @Test + void throwsOnWindowUpdateWrongSize() { + assertThrows(H2Exception.class, () -> decode(buildFrame(8, 0, 0, new byte[3]))); + } + + @Test + void throwsOnRstStreamWrongSize() { + assertThrows(H2Exception.class, () -> decode(buildFrame(3, 0, 1, new byte[3]))); + } + + @Test + void throwsOnPriorityWrongSize() { + assertThrows(H2Exception.class, () -> decode(buildFrame(2, 0, 1, new byte[4]))); + } + + @Test + void throwsOnGoawayTooShort() { + assertThrows(H2Exception.class, () -> decode(buildFrame(7, 0, 0, new byte[7]))); + } + + @Test + void throwsOnPushPromiseTooShort() { + assertThrows(H2Exception.class, () -> decode(buildFrame(5, 0, 1, new byte[3]))); + } + + @Test + void throwsOnPushPromisePaddedTooShort() { + assertThrows(H2Exception.class, () -> decode(buildFrame(5, 0x08, 1, new byte[4]))); + } + + // validateStreamId tests + @Test + void throwsOnDataStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(0, 0, 0, new byte[1]))); + } + + @Test + void throwsOnHeadersStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(1, 0x04, 0, new byte[1]))); + } + + @Test + void throwsOnPriorityStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(2, 0, 0, new byte[5]))); + } + + @Test + void throwsOnRstStreamStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(3, 0, 0, new byte[4]))); + } + + @Test + void throwsOnContinuationStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(9, 0, 0, new byte[1]))); + } + + @Test + void throwsOnSettingsNonZeroStreamId() { + assertThrows(H2Exception.class, () -> decode(buildFrame(4, 0, 1, new byte[0]))); + } + + @Test + void throwsOnPingNonZeroStreamId() { + assertThrows(H2Exception.class, () -> decode(buildFrame(6, 0, 1, new byte[8]))); + } + + @Test + void throwsOnGoawayNonZeroStreamId() { + assertThrows(H2Exception.class, () -> decode(buildFrame(7, 0, 1, new byte[8]))); + } + + @Test + void throwsOnPushPromiseStreamIdZero() { + assertThrows(H2Exception.class, () -> decode(buildFrame(5, 0x04, 0, new byte[4]))); + } + + // Frame size exceeds max during read + @Test + void throwsOnFrameSizeExceedsMax() { + var codec = new H2FrameCodec(wrapIn(buildFrame(0, 0, 1, new byte[200])), + wrapOut(new ByteArrayOutputStream()), + 100); + + assertThrows(H2Exception.class, codec::nextFrame); + } + + // removePadding edge case - empty payload + @Test + void throwsOnPaddedEmptyPayload() { + assertThrows(H2Exception.class, () -> decode(buildFrame(0, 0x08, 1, new byte[0]))); + } + + // PUSH_PROMISE payload too short for promised stream ID (validated at nextFrame() time) + @Test + void throwsOnPushPromisePayloadTooShortForStreamId() { + // Build a PUSH_PROMISE frame with payload too short for stream ID (requires 4 bytes min) + var codec = new H2FrameCodec(wrapIn(buildFrame(5, 0x04, 1, new byte[2])), + wrapOut(new ByteArrayOutputStream()), + 16384); + // Validation now happens at nextFrame() time + assertThrows(H2Exception.class, codec::nextFrame); + } + + // Codec.parseSettings edge cases + @Test + void parseSettingsPayloadNotMultipleOf6() throws IOException { + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(new ByteArrayOutputStream()), 16384); + byte[] payload = new byte[7]; // 7 bytes, not multiple of 6 + + assertThrows(H2Exception.class, () -> codec.parseSettings(payload, 7)); + } + + // Codec.parseGoaway edge cases + @Test + void parseGoawayPayloadTooShort() { + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> codec.parseGoaway(new byte[4], 4)); + } + + // Codec.parseWindowUpdate edge cases + @Test + void parseWindowUpdateWrongPayloadLength() { + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> codec.parseWindowUpdate(new byte[3], 3)); + } + + @Test + void parseWindowUpdateZeroIncrement() throws IOException { + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> codec.parseWindowUpdate(new byte[4], 4)); // all zeros = increment 0 + } + + // Codec.parseRstStream edge cases + @Test + void parseRstStreamWrongPayloadLength() throws IOException { + var codec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(H2Exception.class, () -> codec.parseRstStream(new byte[3], 3)); + } + + // Incomplete payload reads + @Test + void throwsOnIncompletePayload() { + // Build header claiming 8-byte PING payload but only provide 4 bytes + byte[] truncated = new byte[9 + 4]; // header + partial payload + truncated[2] = 8; // length = 8 + truncated[3] = 6; // type = PING + // streamId = 0 (already zeros) + var codec = new H2FrameCodec(wrapIn(truncated), wrapOut(new ByteArrayOutputStream()), 16384); + + assertThrows(IOException.class, () -> { + codec.nextFrame(); + byte[] payload = new byte[codec.framePayloadLength()]; + codec.readPayloadInto(payload, 0, payload.length); + }); + } + + // Helpers + private static final int BUF_SIZE = 8192; + + private ChannelFrameReader wrapIn(byte[] data) { + return new ChannelFrameReader( + Channels.newChannel(new ByteArrayInputStream(data)), + BUF_SIZE); + } + + private ChannelFrameWriter wrapOut(ByteArrayOutputStream out) { + return new ChannelFrameWriter( + Channels.newChannel(out), + BUF_SIZE); + } + + private H2FrameCodec codec(ByteArrayOutputStream out) { + return new H2FrameCodec(wrapIn(new byte[0]), wrapOut(out), 16384); + } + + private TestFrame decode(ByteArrayOutputStream out) throws IOException { + var codec = new H2FrameCodec(wrapIn(out.toByteArray()), wrapOut(new ByteArrayOutputStream()), 16384); + int type = codec.nextFrame(); + int flags = codec.frameFlags(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload; + if (length == 0) { + payload = new byte[0]; + } else { + payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + } + return new TestFrame(type, flags, streamId, payload, length, codec); + } + + private TestFrame decode(byte[] frame) throws IOException { + var codec = new H2FrameCodec(wrapIn(frame), wrapOut(new ByteArrayOutputStream()), 16384); + int type = codec.nextFrame(); + int flags = codec.frameFlags(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload; + if (length == 0) { + payload = new byte[0]; + } else { + payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + } + return new TestFrame(type, flags, streamId, payload, length, codec); + } + + // Decode the first frame of `frame`, read its payload, then run readHeaderBlock with the given cap. + // Returns an exact-length copy of the resulting header block so callers can assert on contents. + private byte[] readHeaderBlockWithCap(byte[] frame, int maxAccumulatedSize) throws IOException { + var codec = new H2FrameCodec(wrapIn(frame), wrapOut(new ByteArrayOutputStream()), 16384); + codec.nextFrame(); + int streamId = codec.frameStreamId(); + int length = codec.framePayloadLength(); + byte[] payload = new byte[length]; + if (length > 0) { + codec.readPayloadInto(payload, 0, length); + } + boolean endHeaders = codec.hasFrameFlag(H2Constants.FLAG_END_HEADERS); + byte[] block = codec.readHeaderBlock(streamId, payload, length, maxAccumulatedSize); + int blockSize = endHeaders ? block.length : codec.headerBlockSize(); + return Arrays.copyOf(block, blockSize); + } + + private void decodeAndReadPayload(byte[] frame) throws IOException { + var codec = new H2FrameCodec(wrapIn(frame), wrapOut(new ByteArrayOutputStream()), 16384); + int type = codec.nextFrame(); + int length = codec.framePayloadLength(); + if (length > 0) { + byte[] payload = new byte[length]; + codec.readPayloadInto(payload, 0, length); + } + } + + private byte[] buildFrame(int type, int flags, int streamId, byte[] payload) { + byte[] frame = new byte[9 + payload.length]; + frame[0] = (byte) ((payload.length >> 16) & 0xFF); + frame[1] = (byte) ((payload.length >> 8) & 0xFF); + frame[2] = (byte) (payload.length & 0xFF); + frame[3] = (byte) type; + frame[4] = (byte) flags; + frame[5] = (byte) ((streamId >> 24) & 0x7F); + frame[6] = (byte) ((streamId >> 16) & 0xFF); + frame[7] = (byte) ((streamId >> 8) & 0xFF); + frame[8] = (byte) (streamId & 0xFF); + System.arraycopy(payload, 0, frame, 9, payload.length); + return frame; + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameTestSuiteTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameTestSuiteTest.java new file mode 100644 index 0000000000..b13da8631b --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2FrameTestSuiteTest.java @@ -0,0 +1,362 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_PADDED; +import static software.amazon.smithy.java.http.client.h2.H2Constants.FLAG_PRIORITY; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * HTTP/2 frame codec test suite using test vectors from http2jp/http2-frame-test-case. + * + *

The {@link #decodeFrame} test validates decoding against upstream JSON test vectors. + * The {@link #roundTripFrame} test validates encode-decode identity using our codec both ways. + * + * @see http2-frame-test-case + */ +class H2FrameTestSuiteTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final String[] FRAME_TYPES = { + "data", + "headers", + "priority", + "rst_stream", + "settings", + "push_promise", + "ping", + "goaway", + "window_update", + "continuation" + }; + + // Codec strips PADDED and PRIORITY flags after processing padding/priority fields + private static final int STRIPPED_FLAGS_MASK = ~(FLAG_PADDED | FLAG_PRIORITY); + + /** + * Helper record that wraps stateful codec API for test convenience. + */ + record TestFrame(int type, int flags, int streamId, byte[] payload, int length, H2FrameCodec codec) { + boolean hasFlag(int flag) { + return (flags & flag) != 0; + } + + int payloadLength() { + return length; + } + + int[] parseSettings() throws H2Exception { + return codec.parseSettings(payload, length); + } + + int[] parseGoaway() throws H2Exception { + return codec.parseGoaway(payload, length); + } + + int parseWindowUpdate() throws H2Exception { + return codec.parseWindowUpdate(payload, length); + } + + int parseRstStream() throws H2Exception { + return codec.parseRstStream(payload, length); + } + } + + /** + * Read a frame using the stateful API and return a TestFrame for convenience. + */ + private static TestFrame readFrame(H2FrameCodec codec) throws IOException { + int type = codec.nextFrame(); + if (type < 0) { + return null; + } + + int flags = codec.frameFlags(); + int streamId = codec.frameStreamId(); + int payloadLength = codec.framePayloadLength(); + + byte[] payload; + if (payloadLength == 0) { + payload = new byte[0]; + } else { + payload = new byte[payloadLength]; + codec.readPayloadInto(payload, 0, payloadLength); + } + + return new TestFrame(type, flags, streamId, payload, payloadLength, codec); + } + + static Stream frameTestCases() throws IOException { + List args = new ArrayList<>(); + + for (String frameType : FRAME_TYPES) { + String[] files = {"normal.json", "error.json"}; + for (String file : files) { + String path = "http2-frame-test-case/" + frameType + "/" + file; + try (InputStream is = H2FrameTestSuiteTest.class.getClassLoader().getResourceAsStream(path)) { + if (is == null) { + // normal.json must exist; error.json is optional + if (file.equals("normal.json")) { + throw new IllegalStateException("Missing frame test resource: " + path); + } + continue; + } + + JsonNode root = MAPPER.readTree(is); + String wire = root.get("wire").asText(); + JsonNode error = root.get("error"); + JsonNode frame = root.get("frame"); + String description = root.has("description") ? root.get("description").asText() : file; + String testName = frameType + "/" + file + ": " + description; + + boolean expectError = error != null && !error.isNull(); + + if (!expectError && frame != null) { + int type = frame.get("type").asInt(); + int flags = frame.get("flags").asInt(); + int streamId = frame.get("stream_identifier").asInt(); + JsonNode framePayload = frame.get("frame_payload"); + + args.add(Arguments.of(testName, wire, false, type, flags, streamId, framePayload)); + } else if (expectError) { + args.add(Arguments.of(testName, wire, true, 0, 0, 0, null)); + } + } + } + } + + return args.stream(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("frameTestCases") + void decodeFrame( + String description, + String wireHex, + boolean expectError, + int expectedType, + int expectedFlags, + int expectedStreamId, + JsonNode framePayload + ) throws IOException { + + byte[] wireBytes = hexToBytes(wireHex); + H2FrameCodec codec = new H2FrameCodec(wrapIn(wireBytes), wrapOut(new ByteArrayOutputStream()), 16384); + + if (expectError) { + assertThrows(IOException.class, () -> readFrame(codec), "Expected error for: " + description); + } else { + TestFrame frame = readFrame(codec); + + assertNotNull(frame, "Frame should not be null for: " + description); + assertEquals(expectedType, frame.type(), "Type mismatch for: " + description); + assertEquals(expectedFlags & STRIPPED_FLAGS_MASK, + frame.flags() & STRIPPED_FLAGS_MASK, + "Flags mismatch for: " + description); + assertEquals(expectedStreamId, frame.streamId(), "Stream ID mismatch for: " + description); + + verifyPayload(frame, framePayload, description); + } + } + + static Stream roundTripTestCases() throws IOException { + List args = new ArrayList<>(); + + for (String frameType : FRAME_TYPES) { + String path = "http2-frame-test-case/" + frameType + "/normal.json"; + try (InputStream is = H2FrameTestSuiteTest.class.getClassLoader().getResourceAsStream(path)) { + if (is == null) { + throw new IllegalStateException("Missing frame test resource: " + path); + } + + JsonNode root = MAPPER.readTree(is); + String wire = root.get("wire").asText(); + String description = root.has("description") ? root.get("description").asText() : "normal"; + args.add(Arguments.of(frameType + ": " + description, wire)); + } + } + + return args.stream(); + } + + @ParameterizedTest(name = "roundtrip {0}") + @MethodSource("roundTripTestCases") + void roundTripFrame(String description, String wireHex) throws IOException { + byte[] wireBytes = hexToBytes(wireHex); + var decodeCodec = new H2FrameCodec(wrapIn(wireBytes), wrapOut(new ByteArrayOutputStream()), 16384); + TestFrame original = readFrame(decodeCodec); + + // Re-encode + var encodeOut = new ByteArrayOutputStream(); + var encodeCodec = new H2FrameCodec(wrapIn(new byte[0]), wrapOut(encodeOut), 16384); + encodeCodec.writeFrame( + original.type(), + original.flags(), + original.streamId(), + original.payload(), + 0, + original.payloadLength()); + encodeCodec.flush(); + + // Decode again + var redecodeCodec = new H2FrameCodec(wrapIn(encodeOut.toByteArray()), + wrapOut(new ByteArrayOutputStream()), + 16384); + TestFrame roundTripped = readFrame(redecodeCodec); + + // Verify matches + assertEquals(original.type(), roundTripped.type(), "Type mismatch after round-trip: " + description); + assertEquals(original.flags(), roundTripped.flags(), "Flags mismatch after round-trip: " + description); + assertEquals(original.streamId(), + roundTripped.streamId(), + "StreamId mismatch after round-trip: " + description); + assertEquals(original.payloadLength(), + roundTripped.payloadLength(), + "Length mismatch after round-trip: " + description); + + byte[] origPayload = new byte[original.payloadLength()]; + byte[] rtPayload = new byte[roundTripped.payloadLength()]; + System.arraycopy(original.payload(), 0, origPayload, 0, original.payloadLength()); + System.arraycopy(roundTripped.payload(), 0, rtPayload, 0, roundTripped.payloadLength()); + assertArrayEquals(origPayload, rtPayload, "Payload mismatch after round-trip: " + description); + } + + private void verifyPayload(TestFrame frame, JsonNode payload, String description) throws IOException { + if (payload == null) { + return; + } + + switch (frame.type()) { + case 0 -> verifyDataPayload(frame, payload, description); // DATA + case 3 -> verifyRstStreamPayload(frame, payload, description); // RST_STREAM + case 4 -> verifySettingsPayload(frame, payload, description); // SETTINGS + case 6 -> verifyPingPayload(frame, payload, description); // PING + case 7 -> verifyGoawayPayload(frame, payload, description); // GOAWAY + case 8 -> verifyWindowUpdatePayload(frame, payload, description); // WINDOW_UPDATE + default -> { + // HEADERS, CONTINUATION, etc. have HPACK-encoded payloads + } + } + } + + private void verifyDataPayload(TestFrame frame, JsonNode payload, String description) { + if (payload.has("data")) { + String expectedData = payload.get("data").asText(); + + // Handle PADDED frames - the raw payload includes: [padLength][data][padding] + int offset = 0; + int dataLength = frame.payloadLength(); + if (frame.hasFlag(FLAG_PADDED) && payload.has("padding_length")) { + int padLength = payload.get("padding_length").asInt(); + offset = 1; // Skip the pad length byte + dataLength = frame.payloadLength() - 1 - padLength; + } + + String actualData = new String(frame.payload(), offset, dataLength, StandardCharsets.UTF_8); + assertEquals(expectedData, actualData, "DATA payload mismatch for: " + description); + } + } + + private void verifyRstStreamPayload(TestFrame frame, JsonNode payload, String description) + throws IOException { + if (payload.has("error_code")) { + int expectedErrorCode = payload.get("error_code").asInt(); + int actualErrorCode = frame.parseRstStream(); + assertEquals(expectedErrorCode, actualErrorCode, "RST_STREAM error_code mismatch for: " + description); + } + } + + private void verifySettingsPayload(TestFrame frame, JsonNode payload, String description) + throws IOException { + if (payload.has("settings")) { + int[] settings = frame.parseSettings(); + JsonNode expectedSettings = payload.get("settings"); + assertEquals(expectedSettings.size() * 2, + settings.length, + "SETTINGS count mismatch for: " + description); + for (int i = 0; i < expectedSettings.size(); i++) { + JsonNode pair = expectedSettings.get(i); + assertEquals(pair.get(0).asInt(), + settings[i * 2], + "SETTINGS id mismatch at " + i + " for: " + description); + assertEquals(pair.get(1).asInt(), + settings[i * 2 + 1], + "SETTINGS value mismatch at " + i + " for: " + description); + } + } + } + + private void verifyPingPayload(TestFrame frame, JsonNode payload, String description) { + if (payload.has("opaque_data")) { + String expectedStr = payload.get("opaque_data").asText(); + byte[] expected = expectedStr.getBytes(StandardCharsets.US_ASCII); + byte[] actual = new byte[frame.payloadLength()]; + System.arraycopy(frame.payload(), 0, actual, 0, frame.payloadLength()); + assertArrayEquals(expected, actual, "PING opaque_data mismatch for: " + description); + } + } + + private void verifyGoawayPayload(TestFrame frame, JsonNode payload, String description) + throws IOException { + int[] goaway = frame.parseGoaway(); + if (payload.has("last_stream_id")) { + assertEquals(payload.get("last_stream_id").asInt(), + goaway[0], + "GOAWAY last_stream_id mismatch for: " + description); + } + if (payload.has("error_code")) { + assertEquals(payload.get("error_code").asInt(), + goaway[1], + "GOAWAY error_code mismatch for: " + description); + } + } + + private void verifyWindowUpdatePayload(TestFrame frame, JsonNode payload, String description) + throws IOException { + if (payload.has("window_size_increment")) { + int expected = payload.get("window_size_increment").asInt(); + int actual = frame.parseWindowUpdate(); + assertEquals(expected, actual, "WINDOW_UPDATE increment mismatch for: " + description); + } + } + + private static byte[] hexToBytes(String hex) { + int len = hex.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + } + return data; + } + + private static final int BUF_SIZE = 8192; + + private static ChannelFrameReader wrapIn(byte[] data) { + return new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(data)), BUF_SIZE); + } + + private static ChannelFrameWriter wrapOut(ByteArrayOutputStream out) { + return new ChannelFrameWriter(Channels.newChannel(out), BUF_SIZE); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2MuxerStreamReleaseTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2MuxerStreamReleaseTest.java new file mode 100644 index 0000000000..a102b4d43a --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2MuxerStreamReleaseTest.java @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.channels.Channels; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class H2MuxerStreamReleaseTest { + + private H2Muxer muxer; + + @BeforeEach + void setUp() { + var codec = new H2FrameCodec( + new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(new byte[0])), + 256), + new ChannelFrameWriter(Channels.newChannel(new ByteArrayOutputStream()), 256), + 16384); + muxer = new H2Muxer( + new H2Muxer.ConnectionCallback() { + @Override + public boolean isAcceptingStreams() { + return true; + } + + @Override + public int getRemoteMaxHeaderListSize() { + return Integer.MAX_VALUE; + } + }, + codec, + 4096, + "test-writer", + 65535); + } + + @AfterEach + void tearDown() { + muxer.close(); + } + + @Test + void releaseStreamInvokesCallback() { + var callCount = new AtomicInteger(0); + muxer.setStreamReleaseCallback(callCount::incrementAndGet); + + // Register a fake stream so releaseStream has something to remove + var exchange = new H2Exchange(muxer, null, 5000, 5000, 65535); + int streamId = muxer.allocateAndRegisterStream(exchange); + + muxer.releaseStream(streamId); + + assertEquals(1, callCount.get(), "Callback should be invoked on stream release"); + } + + @Test + void releaseStreamSlotInvokesCallback() { + var callCount = new AtomicInteger(0); + muxer.setStreamReleaseCallback(callCount::incrementAndGet); + + muxer.releaseStreamSlot(); + + assertEquals(1, callCount.get(), "Callback should be invoked on stream slot release"); + } + + @Test + void releaseStreamDoesNotFailWithoutCallback() { + // No callback set — should not throw + var exchange = new H2Exchange(muxer, null, 5000, 5000, 65535); + int streamId = muxer.allocateAndRegisterStream(exchange); + + muxer.releaseStream(streamId); // should not throw + } + + // Regression: a stream error releases the stream slot, and a racing close/error path that calls + // releaseStream again must be a no-op (only the first release counts). + @Test + void releaseStreamIsIdempotent() { + var callCount = new AtomicInteger(0); + muxer.setStreamReleaseCallback(callCount::incrementAndGet); + + var exchange = new H2Exchange(muxer, null, 5000, 5000, 65535); + int streamId = muxer.allocateAndRegisterStream(exchange); + + muxer.releaseStream(streamId); + muxer.releaseStream(streamId); // second call should be a no-op + + assertEquals(1, callCount.get(), "Callback should fire exactly once across repeated releases"); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2PingAckTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2PingAckTest.java new file mode 100644 index 0000000000..ca74c3db37 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2PingAckTest.java @@ -0,0 +1,73 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; +import org.junit.jupiter.api.Test; + +class H2PingAckTest { + + @Test + void pingResponseFrameHasAckFlag() throws IOException { + // Write a PING frame with ACK=true (as a PING response should be) + var out = new ByteArrayOutputStream(); + var codec = new H2FrameCodec( + new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(new byte[0])), + 256), + new ChannelFrameWriter(Channels.newChannel(out), 256), + 16384); + + byte[] pingPayload = {1, 2, 3, 4, 5, 6, 7, 8}; + codec.writeFrame(H2Constants.FRAME_TYPE_PING, H2Constants.FLAG_ACK, 0, pingPayload); + codec.flush(); + + // Read it back and verify ACK flag is set + var readCodec = new H2FrameCodec( + new ChannelFrameReader( + Channels.newChannel(new ByteArrayInputStream(out.toByteArray())), + 256), + new ChannelFrameWriter(Channels.newChannel(new ByteArrayOutputStream()), 256), + 16384); + int type = readCodec.nextFrame(); + + assertEquals(H2Constants.FRAME_TYPE_PING, type); + assertTrue(readCodec.hasFrameFlag(H2Constants.FLAG_ACK), + "PING response must have ACK flag set"); + } + + @Test + void pingRequestFrameDoesNotHaveAckFlag() throws IOException { + // Write a PING frame without ACK (a PING request) + var out = new ByteArrayOutputStream(); + var codec = new H2FrameCodec( + new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(new byte[0])), + 256), + new ChannelFrameWriter(Channels.newChannel(out), 256), + 16384); + + byte[] pingPayload = {1, 2, 3, 4, 5, 6, 7, 8}; + codec.writeFrame(H2Constants.FRAME_TYPE_PING, 0, 0, pingPayload); + codec.flush(); + + var readCodec = new H2FrameCodec( + new ChannelFrameReader( + Channels.newChannel(new ByteArrayInputStream(out.toByteArray())), + 256), + new ChannelFrameWriter(Channels.newChannel(new ByteArrayOutputStream()), 256), + 16384); + int type = readCodec.nextFrame(); + + assertEquals(H2Constants.FRAME_TYPE_PING, type); + assertFalse(readCodec.hasFrameFlag(H2Constants.FLAG_ACK), "PING request must NOT have ACK flag"); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ReceiveFlowControlTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ReceiveFlowControlTest.java new file mode 100644 index 0000000000..76aa6900d2 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ReceiveFlowControlTest.java @@ -0,0 +1,102 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class H2ReceiveFlowControlTest { + + private static final int INITIAL_WINDOW_SIZE = 8; + + private H2Muxer muxer; + private AtomicInteger connectionCreditReleased; + + @BeforeEach + void setUp() { + connectionCreditReleased = new AtomicInteger(); + var codec = new H2FrameCodec( + new ChannelFrameReader(Channels.newChannel(new ByteArrayInputStream(new byte[0])), + 256), + new ChannelFrameWriter(Channels.newChannel(new ByteArrayOutputStream()), 256), + 16384); + muxer = new H2Muxer( + new H2Muxer.ConnectionCallback() { + @Override + public boolean isAcceptingStreams() { + return true; + } + + @Override + public int getRemoteMaxHeaderListSize() { + return Integer.MAX_VALUE; + } + + @Override + public void releaseConnectionReceiveWindow(int bytes) { + connectionCreditReleased.addAndGet(bytes); + } + }, + codec, + 4096, + "receive-flow-test", + INITIAL_WINDOW_SIZE); + } + + @AfterEach + void tearDown() { + muxer.close(); + } + + @Test + void enqueueDoesNotReleaseReceiveWindowCredit() { + H2Exchange exchange = exchange(); + + exchange.enqueueData(ByteBuffer.wrap(new byte[] {1, 2}), false, false, 4); + + assertEquals(0, connectionCreditReleased.get()); + } + + @Test + void closingDataInputStreamReleasesHeldChunkCredit() throws Exception { + H2Exchange exchange = exchange(); + exchange.deliverHeaders(List.of(":status", "200"), false); + exchange.enqueueData(ByteBuffer.wrap(new byte[] {1, 2}), false, false, 4); + + H2DataInputStream input = new H2DataInputStream(exchange, _buffer -> {}); + assertEquals(2, input.read(new byte[2])); + assertEquals(0, connectionCreditReleased.get()); + + input.close(); + + assertEquals(4, connectionCreditReleased.get()); + } + + @Test + void closingExchangeReleasesQueuedChunkCredit() { + H2Exchange exchange = exchange(); + exchange.enqueueData(ByteBuffer.wrap(new byte[] {1, 2}), false, false, 4); + + exchange.close(); + + assertEquals(4, connectionCreditReleased.get()); + } + + private H2Exchange exchange() { + H2Exchange exchange = new H2Exchange(muxer, null, 5000, 5000, INITIAL_WINDOW_SIZE); + exchange.setStreamId(1); + return exchange; + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessorTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessorTest.java new file mode 100644 index 0000000000..ccb2e3b4f7 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2ResponseHeaderProcessorTest.java @@ -0,0 +1,211 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class H2ResponseHeaderProcessorTest { + + // Helper to create flat header list + private static List headers(String... pairs) { + return List.of(pairs); + } + + @Test + void validResponseHeaders() throws IOException { + var fields = headers( + ":status", + "200", + "content-type", + "application/json", + "content-length", + "42"); + + var result = H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false); + + assertEquals(200, result.statusCode()); + assertEquals(42, result.contentLength()); + assertEquals("application/json", result.headers().firstValue("content-type")); + } + + @Test + void informationalResponse() throws IOException { + var fields = headers(":status", "100"); + + var result = H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false); + + assertTrue(result.isInformational()); + } + + @Test + void informationalResponseWithEndStreamThrows() { + var fields = headers(":status", "100"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, true)); + assertTrue(ex.getMessage().contains("1xx response must not have END_STREAM")); + } + + @Test + void missingStatusThrows() { + var fields = headers("content-type", "text/plain"); + + assertThrows(IOException.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + } + + @Test + void duplicateStatusThrows() { + var fields = headers(":status", "200", ":status", "201"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("single :status")); + } + + @Test + void invalidStatusValueThrows() { + var fields = headers(":status", "abc"); + + assertThrows(IOException.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + } + + @Test + void pseudoHeaderAfterRegularHeaderThrows() { + var fields = headers( + ":status", + "200", + "content-type", + "text/plain", + ":unknown", + "value"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("appears after regular header")); + } + + @Test + void requestPseudoHeaderInResponseThrows() { + var fields = headers(":status", "200", ":method", "GET"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("Request pseudo-header")); + } + + @Test + void unknownPseudoHeaderThrows() { + var fields = headers(":status", "200", ":unknown", "value"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("Unknown pseudo-header")); + } + + @Test + void invalidContentLengthThrows() { + var fields = headers(":status", "200", "content-length", "not-a-number"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("Invalid Content-Length")); + } + + @Test + void multipleConflictingContentLengthThrows() { + var fields = headers( + ":status", + "200", + "content-length", + "100", + "content-length", + "200"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false)); + assertTrue(ex.getMessage().contains("Multiple Content-Length")); + } + + @Test + void duplicateIdenticalContentLengthAllowed() throws IOException { + var fields = headers( + ":status", + "200", + "content-length", + "100", + "content-length", + "100"); + + var result = H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false); + assertEquals(100, result.contentLength()); + } + + @Test + void noContentLengthReturnsMinusOne() throws IOException { + var fields = headers(":status", "200"); + + var result = H2ResponseHeaderProcessor.processResponseHeaders(fields, 1, false); + assertEquals(-1, result.contentLength()); + } + + // === processTrailers === + + @Test + void validTrailers() throws IOException { + var fields = headers( + "x-checksum", + "abc123", + "x-request-id", + "req-456"); + + var trailers = H2ResponseHeaderProcessor.processTrailers(fields, 1); + + assertEquals("abc123", trailers.firstValue("x-checksum")); + assertEquals("req-456", trailers.firstValue("x-request-id")); + } + + @Test + void trailerWithPseudoHeaderThrows() { + var fields = headers(":status", "200"); + + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.processTrailers(fields, 1)); + assertTrue(ex.getMessage().contains("Trailer contains pseudo-header")); + } + + @Test + void emptyTrailersAllowed() throws IOException { + var trailers = H2ResponseHeaderProcessor.processTrailers(List.of(), 1); + assertTrue(trailers.map().isEmpty()); + } + + // === validateContentLength === + + @Test + void contentLengthMatchPasses() throws IOException { + H2ResponseHeaderProcessor.validateContentLength(100, 100, 1); + } + + @Test + void contentLengthMismatchThrows() { + var ex = assertThrows(H2Exception.class, + () -> H2ResponseHeaderProcessor.validateContentLength(100, 50, 1)); + assertTrue(ex.getMessage().contains("Content-Length mismatch")); + } + + @Test + void noContentLengthSkipsValidation() throws IOException { + H2ResponseHeaderProcessor.validateContentLength(-1, 999, 1); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2StreamStateTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2StreamStateTest.java new file mode 100644 index 0000000000..6a3ee61595 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/H2StreamStateTest.java @@ -0,0 +1,131 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class H2StreamStateTest { + + @Test + void initialStateIsCorrect() { + var state = new H2StreamState(); + + assertFalse(state.isResponseHeadersReceived()); + assertFalse(state.isEndStreamSent()); + assertFalse(state.isEndStreamReceived()); + assertEquals(H2StreamState.RS_WAITING, state.getReadState()); + } + + @Test + void setResponseHeadersReceivedTransitionsState() { + var state = new H2StreamState(); + state.setResponseHeadersReceived(200); + + assertTrue(state.isResponseHeadersReceived()); + assertEquals(200, state.getStatusCode()); + assertEquals(H2StreamState.RS_READING, state.getReadState()); + } + + @Test + void markEndStreamSentSetsFlag() { + var state = new H2StreamState(); + state.markEndStreamSent(); + + assertTrue(state.isEndStreamSent()); + } + + @Test + void markEndStreamReceivedSetsReadStateDone() { + var state = new H2StreamState(); + state.setResponseHeadersReceived(200); + state.markEndStreamReceived(); + + assertTrue(state.isEndStreamReceived()); + assertEquals(H2StreamState.RS_DONE, state.getReadState()); + } + + @Test + void setErrorStateSetsReadStateError() { + var state = new H2StreamState(); + state.setErrorState(); + + assertEquals(H2StreamState.RS_ERROR, state.getReadState()); + } + + @Test + void streamStateTransitionsCorrectly() { + var state = new H2StreamState(); + + // Initial: IDLE + assertEquals(H2StreamState.SS_IDLE, state.getStreamState()); + + // After headers encoded without endStream -> OPEN + state.onHeadersEncoded(false); + assertEquals(H2StreamState.SS_OPEN, state.getStreamState()); + + // After headers encoded with endStream -> HALF_CLOSED_LOCAL + var state2 = new H2StreamState(); + state2.onHeadersEncoded(true); + assertEquals(H2StreamState.SS_HALF_CLOSED_LOCAL, state2.getStreamState()); + } + + @Test + void halfClosedLocalToClosedOnEndStreamReceived() { + var state = new H2StreamState(); + state.onHeadersEncoded(true); // IDLE -> HALF_CLOSED_LOCAL + state.setResponseHeadersReceived(200); + + state.markEndStreamReceived(); + + assertEquals(H2StreamState.SS_CLOSED, state.getStreamState()); + } + + @Test + void halfClosedRemoteToClosedOnEndStreamSent() { + var state = new H2StreamState(); + state.onHeadersEncoded(false); // IDLE -> OPEN + state.setResponseHeadersReceived(200); + state.markEndStreamReceived(); // OPEN -> HALF_CLOSED_REMOTE + + assertEquals(H2StreamState.SS_HALF_CLOSED_REMOTE, state.getStreamState()); + + state.markEndStreamSent(); // HALF_CLOSED_REMOTE -> CLOSED + + assertEquals(H2StreamState.SS_CLOSED, state.getStreamState()); + } + + @Test + void setStreamStateClosedWorks() { + var state = new H2StreamState(); + state.setStreamStateClosed(); + + assertEquals(H2StreamState.SS_CLOSED, state.getStreamState()); + } + + @Test + void setReadStateDoneWorks() { + var state = new H2StreamState(); + state.setReadStateDone(); + + assertEquals(H2StreamState.RS_DONE, state.getReadState()); + } + + @Test + void setEndStreamReceivedFlagOnlySetsFlag() { + var state = new H2StreamState(); + state.setResponseHeadersReceived(200); + + state.setEndStreamReceivedFlag(); + + assertTrue(state.isEndStreamReceived()); + assertEquals(H2StreamState.RS_DONE, state.getReadState()); + // Stream state should NOT change (unlike markEndStreamReceived) + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderFuzzTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderFuzzTest.java new file mode 100644 index 0000000000..ecefae4c76 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderFuzzTest.java @@ -0,0 +1,156 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.code_intelligence.jazzer.junit.FuzzTest; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http2.DefaultHttp2HeadersDecoder; +import io.netty.handler.codec.http2.Http2Headers; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Fuzz tests for HPACK decoder. + * + *

Tests crash safety, differential correctness against Netty, + * property-based invariants, resource limits, and state machine consistency. + */ +class HpackDecoderFuzzTest { + + // --- Crash safety --- + + private static final int MAX_FUZZ_INPUT = 512; + + @FuzzTest(maxDuration = "5m") + void fuzzDecode(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + try { + new HpackDecoder(4096).decode(data); + } catch (IOException ignored) {} + } + + // --- Differential testing against Netty --- + + @FuzzTest + void fuzzDifferentialVsNetty(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + // Decode with our implementation + var smithyDecoder = new HpackDecoder(4096); + List smithyResult = null; + Exception smithyError = null; + try { + smithyResult = smithyDecoder.decode(data); + } catch (Exception e) { + smithyError = e; + } + + // Decode with Netty + var nettyDecoder = new DefaultHttp2HeadersDecoder(); + Http2Headers nettyResult = null; + Exception nettyError = null; + try { + nettyResult = nettyDecoder.decodeHeaders(1, Unpooled.wrappedBuffer(data)); + } catch (Exception e) { + nettyError = e; + } + + // Both should agree on success/failure + if (smithyError != null && nettyError != null) { + return; // Both rejected — fine + } + if (smithyError == null && nettyError == null) { + // Both succeeded — compare results + int smithyCount = smithyResult.size() / 2; + int nettyCount = nettyResult.size(); + // Netty includes pseudo-headers in the count differently, so just verify + // we decoded the same number of headers + assertEquals(nettyCount, + smithyCount, + "Header count mismatch: smithy=" + smithyCount + " netty=" + nettyCount); + } + // One succeeded and one failed — this is acceptable because implementations + // may differ on strictness (e.g., header validation, size limits) + } + + // --- Property-based invariants: encode → decode round-trip --- + + @FuzzTest + void fuzzRoundTrip(byte[] data) throws IOException { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + if (data.length < 4) { + return; + } + + // Use fuzz data to generate header name/value pairs + var headers = extractHeaders(data); + if (headers.isEmpty()) { + return; + } + + // Encode with our encoder + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + for (int i = 0; i < headers.size(); i += 2) { + encoder.encodeHeader(out, headers.get(i), headers.get(i + 1), false); + } + byte[] encoded = out.toByteArray(); + + // Decode and verify + var decoder = new HpackDecoder(4096); + List decoded = decoder.decode(encoded); + + assertEquals(headers.size(), decoded.size(), "Round-trip header count mismatch"); + for (int i = 0; i < headers.size(); i += 2) { + assertEquals(headers.get(i), decoded.get(i), "Name mismatch at " + (i / 2)); + assertEquals(headers.get(i + 1), decoded.get(i + 1), "Value mismatch at " + (i / 2)); + } + } + + /** + * Extract lowercase header name/value pairs from fuzz data. + */ + private static List extractHeaders(byte[] data) { + var headers = new ArrayList(); + int pos = 0; + while (pos + 2 < data.length && headers.size() < 20) { + int nameLen = (data[pos] & 0x0F) + 1; // 1-16 + pos++; + if (pos + nameLen >= data.length) { + break; + } + // Build lowercase ASCII name + var name = new StringBuilder(nameLen); + for (int i = 0; i < nameLen; i++) { + name.append((char) ('a' + ((data[pos + i] & 0xFF) % 26))); + } + pos += nameLen; + + int valueLen = data[pos] & 0x3F; // 0-63 + pos++; + if (pos + valueLen > data.length) { + break; + } + var value = new String(data, pos, valueLen, StandardCharsets.ISO_8859_1); + pos += valueLen; + + headers.add(name.toString()); + headers.add(value); + } + return headers; + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderTest.java new file mode 100644 index 0000000000..9ffe982491 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackDecoderTest.java @@ -0,0 +1,161 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class HpackDecoderTest { + + @Test + void decodesIndexedNameFromDynamicTable() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + // First block - add custom header to dynamic table + var out1 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out1); + encoder.encodeHeader(out1, "x-custom-name", "value1", false); + decoder.decode(out1.toByteArray()); + + // Second block - use indexed name from dynamic table with new value + var out2 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out2); + encoder.encodeHeader(out2, "x-custom-name", "value2", false); + List headers = decoder.decode(out2.toByteArray()); + + assertEquals(2, headers.size()); // name, value + assertEquals("x-custom-name", headers.get(0)); + assertEquals("value2", headers.get(1)); + } + + @Test + void throwsOnStringLengthExceedsBuffer() { + // Craft a malformed HPACK block: literal with indexing, new name + // 0x40 = literal with indexing, name index 0 (new name) + // 0x05 = string length 5 (but we only provide 2 bytes) + byte[] malformed = {0x40, 0x05, 'a', 'b'}; + var decoder = new HpackDecoder(4096); + + assertThrows(IOException.class, () -> decoder.decode(malformed)); + } + + @Test + void throwsOnDynamicTableSizeUpdateAfterHeader() { + // Craft: indexed header (0x82 = :method GET), then table size update (0x20) + byte[] malformed = {(byte) 0x82, 0x20}; + var decoder = new HpackDecoder(4096); + + IOException ex = assertThrows(IOException.class, () -> decoder.decode(malformed)); + assertTrue(ex.getMessage().contains("beginning of header block")); + } + + @Test + void throwsOnHeaderListExceedsMaxSize() { + // Create decoder with small max header list size + var decoder = new HpackDecoder(4096, 50); + + // Encode a header that exceeds the limit (name + value + 32 overhead) + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + try { + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, "x-long-header-name", "this-is-a-long-value", false); + } catch (IOException e) { + throw new RuntimeException(e); + } + + IOException ex = assertThrows(IOException.class, () -> decoder.decode(out.toByteArray())); + assertTrue(ex.getMessage().contains("exceeds maximum size")); + } + + @Test + void throwsOnUppercaseHeaderName() { + // Craft: literal without indexing (0x00), name length 4, "Test" (uppercase T) + byte[] malformed = {0x00, 0x04, 'T', 'e', 's', 't', 0x05, 'v', 'a', 'l', 'u', 'e'}; + var decoder = new HpackDecoder(4096); + + IOException ex = assertThrows(IOException.class, () -> decoder.decode(malformed)); + assertTrue(ex.getMessage().contains("uppercase")); + } + + @Test + void allowsTableSizeUpdateAtBeginning() throws IOException { + // Table size update (0x20 = size 0) followed by indexed header (0x82 = :method GET) + byte[] valid = {0x20, (byte) 0x82}; + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(valid); + + assertEquals(2, headers.size()); + assertEquals(":method", headers.get(0)); + assertEquals("GET", headers.get(1)); + } + + @Test + void decodesLiteralNeverIndexed() throws IOException { + // 0x10 = literal never indexed, name index 0 + byte[] data = {0x10, 0x04, 't', 'e', 's', 't', 0x05, 'v', 'a', 'l', 'u', 'e'}; + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(data); + + assertEquals(2, headers.size()); + assertEquals("test", headers.get(0)); + assertEquals("value", headers.get(1)); + } + + @Test + void decodesLiteralWithoutIndexing() throws IOException { + // 0x00 = literal without indexing, name index 0 + byte[] data = {0x00, 0x04, 't', 'e', 's', 't', 0x05, 'v', 'a', 'l', 'u', 'e'}; + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(data); + + assertEquals(2, headers.size()); + assertEquals("test", headers.get(0)); + assertEquals("value", headers.get(1)); + } + + @Test + void throwsOnInvalidIndex() { + // 0x80 = indexed with index 0 (invalid) + byte[] malformed = {(byte) 0x80}; + var decoder = new HpackDecoder(4096); + + assertThrows(IOException.class, () -> decoder.decode(malformed)); + } + + @Test + void throwsOnIncompleteInteger() { + // 0xff = indexed with index >= 127, needs continuation byte + byte[] malformed = {(byte) 0xff}; + var decoder = new HpackDecoder(4096); + + assertThrows(IOException.class, () -> decoder.decode(malformed)); + } + + @Test + void throwsOnIntegerOverflow() { + // Craft an integer that would overflow (too many continuation bytes) + byte[] malformed = { + (byte) 0xff, // indexed, index >= 127 + (byte) 0xff, + (byte) 0xff, + (byte) 0xff, + (byte) 0xff, + (byte) 0x0f + }; + + var decoder = new HpackDecoder(4096); + + assertThrows(IOException.class, () -> decoder.decode(malformed)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackEncoderTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackEncoderTest.java new file mode 100644 index 0000000000..e52780a9c1 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackEncoderTest.java @@ -0,0 +1,232 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class HpackEncoderTest { + + @Test + void encodesStaticIndexedHeader() throws IOException { + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, ":method", "GET", false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals(":method", headers.get(0)); + assertEquals("GET", headers.get(1)); + } + + @Test + void encodesLiteralWithIndexing() throws IOException { + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, "x-custom", "value", false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals("x-custom", headers.get(0)); + assertEquals("value", headers.get(1)); + } + + @Test + void encodesMultipleHeaders() throws IOException { + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, ":method", "GET", false); + encoder.encodeHeader(out, ":path", "/", false); + encoder.encodeHeader(out, ":scheme", "https", false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(6, headers.size()); // 3 headers * 2 + assertEquals(":method", headers.get(0)); + assertEquals("GET", headers.get(1)); + assertEquals(":path", headers.get(2)); + assertEquals("/", headers.get(3)); + assertEquals(":scheme", headers.get(4)); + assertEquals("https", headers.get(5)); + } + + @Test + void reusesDynamicTableEntry() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + // First block - adds to dynamic table + var out1 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out1); + encoder.encodeHeader(out1, "x-custom", "value", false); + decoder.decode(out1.toByteArray()); + int firstSize = out1.size(); + + // Second block - should use indexed from dynamic table + var out2 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out2); + encoder.encodeHeader(out2, "x-custom", "value", false); + List headers = decoder.decode(out2.toByteArray()); + int secondSize = out2.size(); + + assertEquals(2, headers.size()); + assertEquals("x-custom", headers.get(0)); + assertEquals("value", headers.get(1)); + // Second encoding should be smaller (indexed reference) + assertTrue(secondSize < firstSize); + } + + @Test + void encodesSensitiveHeaderNeverIndexed() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + // First block - sensitive header + var out1 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out1); + encoder.encodeHeader(out1, "x-secret", "password", true); + decoder.decode(out1.toByteArray()); + + // Second block - same header should NOT be indexed + var out2 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out2); + encoder.encodeHeader(out2, "x-secret", "password", true); + List headers = decoder.decode(out2.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals("x-secret", headers.get(0)); + // Size should be same (not indexed) + assertEquals(out1.size(), out2.size()); + } + + @Test + void authorizationHeaderNeverIndexed() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + // First block + var out1 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out1); + encoder.encodeHeader(out1, "authorization", "Bearer token", false); + decoder.decode(out1.toByteArray()); + + // Second block - should NOT be indexed even though sensitive=false + var out2 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out2); + encoder.encodeHeader(out2, "authorization", "Bearer token", false); + List headers = decoder.decode(out2.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals("authorization", headers.get(0)); + // Size should be same (not indexed) + assertEquals(out1.size(), out2.size()); + } + + @Test + void encodesWithoutHuffman() throws IOException { + var encoder = new HpackEncoder(4096, false); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, "x-test", "hello", false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals("x-test", headers.get(0)); + assertEquals("hello", headers.get(1)); + } + + @Test + void emitsTableSizeUpdate() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + // Change table size + encoder.setMaxTableSize(2048); + + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + encoder.encodeHeader(out, ":method", "GET", false); + + // Decoder should handle the table size update + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals(":method", headers.get(0)); + } + + @Test + void tableSizeUpdateOnlyEmittedOnce() throws IOException { + var encoder = new HpackEncoder(4096); + var decoder = new HpackDecoder(4096); + + encoder.setMaxTableSize(2048); + + // First block - should emit table size update + var out1 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out1); + encoder.encodeHeader(out1, ":method", "GET", false); + decoder.decode(out1.toByteArray()); + int firstSize = out1.size(); + + // Second block - should NOT emit table size update again + var out2 = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out2); + encoder.encodeHeader(out2, ":method", "GET", false); + decoder.decode(out2.toByteArray()); + int secondSize = out2.size(); + + // Second should be smaller (no table size update prefix) + assertTrue(secondSize < firstSize); + } + + @Test + void encodesLargeInteger() throws IOException { + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + // Use a long value that requires multi-byte integer encoding + String longValue = "x".repeat(200); + encoder.encodeHeader(out, "x-long", longValue, false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals("x-long", headers.get(0)); + assertEquals(longValue, headers.get(1)); + } + + @Test + void encodesStaticNameWithNewValue() throws IOException { + var encoder = new HpackEncoder(4096); + var out = new ByteArrayOutputStream(); + encoder.beginHeaderBlock(out); + // :path is in static table, but /custom is not + encoder.encodeHeader(out, ":path", "/custom/path", false); + + var decoder = new HpackDecoder(4096); + List headers = decoder.decode(out.toByteArray()); + + assertEquals(2, headers.size()); + assertEquals(":path", headers.get(0)); + assertEquals("/custom/path", headers.get(1)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackTestSuiteTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackTestSuiteTest.java new file mode 100644 index 0000000000..38d48b9012 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HpackTestSuiteTest.java @@ -0,0 +1,117 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * HPACK decoder test suite using test vectors from http2jp/hpack-test-case. + * + *

These test vectors are from the nghttp2 implementation and cover various + * HPACK encoding scenarios including Huffman encoding, dynamic table operations, + * and indexed headers. + * + * @see hpack-test-case + */ +class HpackTestSuiteTest { + + // Cache decoders per story file to maintain dynamic table state across cases + private static final Map DECODERS = new ConcurrentHashMap<>(); + private static final ObjectMapper MAPPER = new ObjectMapper(); + + static Stream hpackTestCases() throws IOException { + List args = new ArrayList<>(); + + for (int i = 0; i <= 31; i++) { + String filename = String.format("hpack-test-case/story_%02d.json", i); + InputStream is = HpackTestSuiteTest.class.getClassLoader().getResourceAsStream(filename); + if (is == null) { + continue; + } + + JsonNode root = MAPPER.readTree(is); + JsonNode cases = root.get("cases"); + if (cases == null) { + continue; + } + + for (JsonNode testCase : cases) { + int seqno = testCase.get("seqno").asInt(); + String wire = testCase.get("wire").asText(); + JsonNode headers = testCase.get("headers"); + + List expectedHeaders = new ArrayList<>(); + for (JsonNode header : headers) { + var fields = header.fields(); + while (fields.hasNext()) { + var field = fields.next(); + expectedHeaders.add(new String[] {field.getKey(), field.getValue().asText()}); + } + } + + args.add(Arguments.of(filename, seqno, wire, expectedHeaders)); + } + } + + return args.stream(); + } + + @ParameterizedTest(name = "{0} case {1}") + @MethodSource("hpackTestCases") + void decodeTestCase(String filename, int seqno, String wireHex, List expectedHeaders) + throws IOException { + // Each story uses a shared decoder to maintain dynamic table state across cases + HpackDecoder decoder = getDecoderForStory(filename); + + // Decode this case's wire bytes + byte[] wireBytes = hexToBytes(wireHex); + List result = decoder.decode(wireBytes); + + // Verify the decoded headers match expected (result is flat: name0, value0, name1, value1, ...) + assertEquals(expectedHeaders.size(), + result.size() / 2, + "Header count mismatch for " + filename + " case " + seqno); + + for (int i = 0; i < expectedHeaders.size(); i++) { + String[] expected = expectedHeaders.get(i); + String actualName = result.get(i * 2); + String actualValue = result.get(i * 2 + 1); + + assertEquals(expected[0], + actualName, + "Header name mismatch at index " + i + " for " + filename + " case " + seqno); + assertEquals(expected[1], + actualValue, + "Header value mismatch at index " + i + " for " + filename + " case " + seqno); + } + } + + private HpackDecoder getDecoderForStory(String filename) { + return DECODERS.computeIfAbsent(filename, k -> new HpackDecoder(4096)); + } + + private static byte[] hexToBytes(String hex) { + int len = hex.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + } + return data; + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanFuzzTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanFuzzTest.java new file mode 100644 index 0000000000..2cf8725be6 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanFuzzTest.java @@ -0,0 +1,58 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.code_intelligence.jazzer.junit.FuzzTest; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Fuzz tests for Huffman codec. + */ +class HuffmanFuzzTest { + + private static final int MAX_FUZZ_INPUT = 1024; + + @FuzzTest + void fuzzDecode(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + try { + Huffman.decode(data, 0, data.length); + } catch (IOException ignored) {} + } + + @FuzzTest + void fuzzDecodeHeaderName(byte[] data) { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + try { + Huffman.decodeHeaderName(data, 0, data.length); + } catch (IOException ignored) {} + } + + @FuzzTest + void fuzzEncode(byte[] data) throws IOException { + if (data.length > MAX_FUZZ_INPUT) { + return; + } + + // Verify encodedLength prediction matches actual encode + var out = new ByteArrayOutputStream(); + Huffman.encode(data, 0, data.length, out); + byte[] encoded = out.toByteArray(); + + int predictedLen = Huffman.encodedLength(data, 0, data.length); + assertEquals(encoded.length, + predictedLen, + "encodedLength prediction mismatch"); + } + +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanTest.java new file mode 100644 index 0000000000..e77cfc6420 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/HuffmanTest.java @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +/** + * Minimal API surface tests for Huffman. Comprehensive coverage is in HpackTestSuiteTest. + */ +class HuffmanTest { + + @Test + void roundTrip() throws IOException { + String input = "hello"; + byte[] inputBytes = input.getBytes(StandardCharsets.ISO_8859_1); + + var out = new ByteArrayOutputStream(); + Huffman.encode(inputBytes, 0, inputBytes.length, out); + byte[] encoded = out.toByteArray(); + + String decoded = Huffman.decode(encoded, 0, encoded.length); + assertEquals(input, decoded); + } + + @Test + void encodedLengthMatchesActual() throws IOException { + byte[] input = "www.example.com".getBytes(StandardCharsets.ISO_8859_1); + int predicted = Huffman.encodedLength(input, 0, input.length); + + var out = new ByteArrayOutputStream(); + Huffman.encode(input, 0, input.length, out); + + assertEquals(predicted, out.size()); + } + + @Test + void emptyInput() throws IOException { + byte[] empty = new byte[0]; + + var out = new ByteArrayOutputStream(); + Huffman.encode(empty, 0, 0, out); + assertEquals(0, out.size()); + + assertEquals("", Huffman.decode(empty, 0, 0)); + assertEquals(0, Huffman.encodedLength(empty, 0, 0)); + } + + @Test + void incompleteEncodingThrows() { + // Single byte that starts a multi-byte sequence but doesn't complete it. + // '0' is 5 bits, needs padding but 0x00 has wrong padding. + byte[] incomplete = {(byte) 0x00}; + + assertThrows(IOException.class, () -> Huffman.decode(incomplete, 0, incomplete.length)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StaticTableTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StaticTableTest.java new file mode 100644 index 0000000000..a014d050c3 --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StaticTableTest.java @@ -0,0 +1,113 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.java.http.api.HeaderName; + +class StaticTableTest { + + @Test + void sizeIs61() { + assertEquals(61, StaticTable.SIZE); + } + + @ParameterizedTest(name = "index {0}: {1}={2}") + @MethodSource("staticTableEntries") + void getReturnsCorrectEntry(int index, String expectedName, String expectedValue) { + assertEquals(expectedName, StaticTable.getName(index)); + assertEquals(expectedValue, StaticTable.getValue(index)); + } + + static Stream staticTableEntries() { + return Stream.of( + Arguments.of(1, ":authority", ""), + Arguments.of(2, ":method", "GET"), + Arguments.of(3, ":method", "POST"), + Arguments.of(4, ":path", "/"), + Arguments.of(5, ":path", "/index.html"), + Arguments.of(6, ":scheme", "http"), + Arguments.of(7, ":scheme", "https"), + Arguments.of(8, ":status", "200"), + Arguments.of(9, ":status", "204"), + Arguments.of(14, ":status", "500"), + Arguments.of(16, "accept-encoding", "gzip, deflate"), + Arguments.of(28, "content-length", ""), + Arguments.of(31, "content-type", ""), + Arguments.of(38, "host", ""), + Arguments.of(61, "www-authenticate", "")); + } + + @ParameterizedTest(name = "findFullMatch({0}, {1}) = {2}") + @MethodSource("fullMatchCases") + void findFullMatch(String name, String value, int expectedIndex) { + assertEquals(expectedIndex, StaticTable.findFullMatch(name, value)); + } + + static Stream fullMatchCases() { + return Stream.of( + Arguments.of(":method", "GET", 2), + Arguments.of(":method", "POST", 3), + Arguments.of(":path", "/", 4), + Arguments.of(":path", "/index.html", 5), + Arguments.of(":scheme", "http", 6), + Arguments.of(":scheme", "https", 7), + Arguments.of(":status", "200", 8), + Arguments.of(":status", "404", 13), + Arguments.of("accept-encoding", "gzip, deflate", 16), + Arguments.of(":method", "PUT", -1), + Arguments.of(":status", "201", -1), + Arguments.of("x-custom", "value", -1), + Arguments.of("content-type", "application/json", -1)); + } + + @ParameterizedTest(name = "findNameMatch({0}) = {1}") + @MethodSource("nameMatchCases") + void findNameMatch(String name, int expectedIndex) { + assertEquals(expectedIndex, StaticTable.findNameMatch(name)); + } + + static Stream nameMatchCases() { + return Stream.of( + Arguments.of(":authority", 1), + Arguments.of(":method", 2), + Arguments.of(":path", 4), + Arguments.of(":scheme", 6), + Arguments.of(":status", 8), + Arguments.of("accept", 19), + Arguments.of("content-length", 28), + Arguments.of("content-type", 31), + Arguments.of("host", 38), + Arguments.of("www-authenticate", 61), + Arguments.of("x-custom", -1), + Arguments.of("x-request-id", -1)); + } + + @Test + void findFullMatchWithHeaderNamesConstant() { + assertEquals(2, StaticTable.findFullMatch(HeaderName.PSEUDO_METHOD.name(), "GET")); + assertEquals(8, StaticTable.findFullMatch(HeaderName.PSEUDO_STATUS.name(), "200")); + } + + @Test + void findNameMatchWithHeaderNamesConstant() { + assertEquals(1, StaticTable.findNameMatch(HeaderName.PSEUDO_AUTHORITY.name())); + assertEquals(31, StaticTable.findNameMatch(HeaderName.CONTENT_TYPE.name())); + } + + @Test + void veryLongNameReturnsNoMatch() { + String longName = "x".repeat(100); + assertEquals(-1, StaticTable.findFullMatch(longName, "value")); + assertEquals(-1, StaticTable.findNameMatch(longName)); + } +} diff --git a/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StreamRegistryTest.java b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StreamRegistryTest.java new file mode 100644 index 0000000000..39faeb54ad --- /dev/null +++ b/http/http-client/src/test/java/software/amazon/smithy/java/http/client/h2/StreamRegistryTest.java @@ -0,0 +1,192 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.http.client.h2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StreamRegistryTest { + + private StreamRegistry registry; + private H2Muxer muxer; + + @BeforeEach + void setUp() { + registry = new StreamRegistry(); + // Create a muxer with minimal dependencies + H2Muxer.ConnectionCallback callback = new H2Muxer.ConnectionCallback() { + @Override + public boolean isAcceptingStreams() { + return true; + } + + @Override + public int getRemoteMaxHeaderListSize() { + return Integer.MAX_VALUE; + } + }; + H2FrameCodec codec = new H2FrameCodec(null, null, 16384); + muxer = new H2Muxer(callback, codec, 4096, "test-muxer", 65535); + } + + @AfterEach + void tearDown() { + if (muxer != null) { + muxer.shutdownNow(); + } + } + + private H2Exchange exchange(int streamId) { + H2Exchange ex = new H2Exchange(muxer, null, 0, 0, 65535); + ex.setStreamId(streamId); + return ex; + } + + @Test + void putAndGet() { + var ex = exchange(1); + registry.put(1, ex); + + assertSame(ex, registry.get(1)); + } + + @Test + void getReturnsNullForMissing() { + assertNull(registry.get(1)); + } + + @Test + void removeFromFastPath() { + var ex = exchange(1); + registry.put(1, ex); + + assertTrue(registry.remove(1)); + assertNull(registry.get(1)); + } + + @Test + void removeReturnsFalseForMissing() { + assertFalse(registry.remove(1)); + } + + @Test + void multipleStreams() { + var ex1 = exchange(1); + var ex3 = exchange(3); + var ex5 = exchange(5); + + registry.put(1, ex1); + registry.put(3, ex3); + registry.put(5, ex5); + + assertSame(ex1, registry.get(1)); + assertSame(ex3, registry.get(3)); + assertSame(ex5, registry.get(5)); + } + + @Test + void spilloverOnCollision() { + // Stream IDs that map to the same slot (4096 slots, so IDs 1 and 1 + 4096*2 = 8193 collide) + int id1 = 1; + int id2 = 1 + 4096 * 2; // 8193 + + var ex1 = exchange(id1); + var ex2 = exchange(id2); + + registry.put(id1, ex1); + registry.put(id2, ex2); // Should spill over + + assertSame(ex1, registry.get(id1)); + assertSame(ex2, registry.get(id2)); + } + + @Test + void removeFromSpillover() { + int id1 = 1; + int id2 = 1 + 4096 * 2; + + var ex1 = exchange(id1); + var ex2 = exchange(id2); + + registry.put(id1, ex1); + registry.put(id2, ex2); + + assertTrue(registry.remove(id2)); // Remove from spillover + assertNull(registry.get(id2)); + assertSame(ex1, registry.get(id1)); // Original still there + } + + @Test + void forEach() { + var ex1 = exchange(1); + var ex3 = exchange(3); + + registry.put(1, ex1); + registry.put(3, ex3); + + List seen = new ArrayList<>(); + registry.forEach(seen, (ex, list) -> list.add(ex.getStreamId())); + + assertEquals(2, seen.size()); + assertTrue(seen.contains(1)); + assertTrue(seen.contains(3)); + } + + @Test + void forEachIncludesSpillover() { + int id1 = 1; + int id2 = 1 + 4096 * 2; + + registry.put(id1, exchange(id1)); + registry.put(id2, exchange(id2)); + + AtomicInteger count = new AtomicInteger(); + registry.forEach(null, (ex, ctx) -> count.incrementAndGet()); + + assertEquals(2, count.get()); + } + + @Test + void forEachMatching() { + registry.put(1, exchange(1)); + registry.put(3, exchange(3)); + registry.put(5, exchange(5)); + + List matched = new ArrayList<>(); + registry.forEachMatching(id -> id > 2, ex -> matched.add(ex.getStreamId())); + + assertEquals(2, matched.size()); + assertTrue(matched.contains(3)); + assertTrue(matched.contains(5)); + } + + @Test + void clearAndClose() { + registry.put(1, exchange(1)); + registry.put(3, exchange(3)); + + int id2 = 1 + 4096 * 2; // Collides with slot for ID 1 + registry.put(id2, exchange(id2)); // spillover + + AtomicInteger closed = new AtomicInteger(); + registry.clearAndClose(ex -> closed.incrementAndGet()); + + assertEquals(3, closed.get()); + assertNull(registry.get(1)); + assertNull(registry.get(3)); + assertNull(registry.get(id2)); + } +} diff --git a/http/http-client/src/test/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider b/http/http-client/src/test/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider new file mode 100644 index 0000000000..072a7f3779 --- /dev/null +++ b/http/http-client/src/test/resources/META-INF/services/software.amazon.smithy.java.http.client.connection.TlsProvider @@ -0,0 +1,2 @@ +software.amazon.smithy.java.http.client.connection.AvailableTestTlsProvider +software.amazon.smithy.java.http.client.connection.UnavailableTestTlsProvider diff --git a/http/http-client/src/test/resources/hpack-test-case/LICENSE b/http/http-client/src/test/resources/hpack-test-case/LICENSE new file mode 100644 index 0000000000..91f2da1c54 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/LICENSE @@ -0,0 +1,22 @@ +The test vectors in this directory are from the hpack-test-case project: +https://github.com/http2jp/hpack-test-case + +Copyright (c) 2013 HTTP/2 Japan Community + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/http/http-client/src/test/resources/hpack-test-case/story_00.json b/http/http-client/src/test/resources/hpack-test-case/story_00.json new file mode 100644 index 0000000000..9546126cfa --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_00.json @@ -0,0 +1,59 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864188f439ce75c875fa5784", + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yahoo.co.jp" + }, + { + ":path": "/" + } + ] + }, + { + "seqno": 1, + "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84", + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/" + } + ] + }, + { + "seqno": 2, + "wire": "82864187eabfa35332fd2b049b60d48e62a1849eb611589825353141e63ad52160b206c4f2f5d537", + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/cmn/logo-ns-130528.png" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_01.json b/http/http-client/src/test/resources/hpack-test-case/story_01.json new file mode 100644 index 0000000000..ad7fca2b77 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_01.json @@ -0,0 +1,56 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8741882f91d35d055c87a784827a879eb193aac92a136087f3e7cf9f3e7c874086f2b4e5a283ff84f07b2893", + "headers": [ + { + ":scheme": "https" + }, + { + ":authority": "example.com" + }, + { + ":path": "/" + }, + { + ":method": "GET" + }, + { + "user-agent": "hpack-test" + }, + { + "cookie": "xxxxxxx1" + }, + { + "x-hello": "world" + } + ] + }, + { + "seqno": 1, + "wire": "87c18482c06087f3e7cf9f3e7c8b", + "headers": [ + { + ":scheme": "https" + }, + { + ":authority": "example.com" + }, + { + ":path": "/" + }, + { + ":method": "GET" + }, + { + "user-agent": "hpack-test" + }, + { + "cookie": "xxxxxxx2" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_02.json b/http/http-client/src/test/resources/hpack-test-case/story_02.json new file mode 100644 index 0000000000..de61e44708 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_02.json @@ -0,0 +1,359 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "828641871d23f67a9721e9847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "82864191996293cae6a473150b0e91fb3d4b90f4ff04ab60d48e62a18c4c002c4d51d88ca321ea62e94643d5babb0c92adc372c00af17168017c0cb6cb712f5d537fc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c073919d29aee30c78f1e171d23f67a9721e963f", + "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/" + } + ] + }, + { + "seqno": 2, + "wire": "8286c004ad60d48e62a18c4c002c795a83907415821e9a4f5309b07522b1d85a92b566f25a178b8b2f38fb4269c6a25e634bc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c004bf60d48e62a18c4c002c1a9982260e99cb63121903424b62d61683165619001621e8b69a9840ea93d2d61683165899003cbadaf171680071e7da7c312f5d537fc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286418bf1e3c2e3a47ecf52e43d3f84c5c4c390c2", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286c104ad60d48e62a18c4c002c795a83907415821e9a4f5309b07522b1d85a92b566f25a178b885f109969c75b89798d2fc5c0c390c2bf", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286c104c160d48e62a18c4c002c1a9982261139ca86103a0a888bdcb5250c0431547eec040c82284842a107b0c546bdbab46a8b172b0d34e95e2e2d000e09c7db044bcc697fc5c0c390c2bf", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c104ac60d48e62a18c4c002c436a4f49d26ee562c3a4e862fdb60c85a287000882202f1710be2101a75c6a25fa5737c5c0c390c2bf", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286c104b060d48e62a18c4c002c5a662838e4c9548620d27b10c5071c992a90c41a4f62d40ec98abc5c42f882fb6d3c089798d2ffc5c0c390c2bf", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286418f293cae6a473150b0e91fb3d4b90f4f049a60d48e62a18c8c341c7fab69beb6ee19d78b7670b2dc4bf4ae6fc6c1c490c3c0", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_03.json b/http/http-client/src/test/resources/hpack-test-case/story_03.json new file mode 100644 index 0000000000..e68346c43d --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_03.json @@ -0,0 +1,362 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "828641878c6692d5c87a7f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286c204896251f7310f52e621ffc1c0bf90be", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418af1e3c2f18cd25ab90f4f84c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286be049060d4ccc4633496c48f541e6385798d2fc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c073909d29aee30c78f1e178c6692d5c87a58f60a4bb0e4bfc325f82eb8165c86f04182ee0042f61bd7c417305d71abcd5e0c2ddeb9871401f", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286c10491608324e5626a0f18e860d4ccc4c85e634bc5c0c390c2bfbe", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286418a40578e442469311721e9049f62c63c78f0c10649cac4d41e31d0c7443091d53583a560aecaed102b817e88c653032a2f2ac590c4c1", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286bf049962c63c78f0c10649cac4d41e31d0c7443139e92ac15de5fa23c7bec590c4c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286bf049762c63c78f0c10649cac5a82d8c744316ac15d95da5fa23c7bec590c4c1", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286bf049162c63c78f0c1a999832c15c0b817aea9bfc7c2c590c4c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c304896251f7310f52e621ffc7c6c590c4c0", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_04.json b/http/http-client/src/test/resources/hpack-test-case/story_04.json new file mode 100644 index 0000000000..e68346c43d --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_04.json @@ -0,0 +1,362 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "828641878c6692d5c87a7f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286c204896251f7310f52e621ffc1c0bf90be", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418af1e3c2f18cd25ab90f4f84c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286be049060d4ccc4633496c48f541e6385798d2fc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c073909d29aee30c78f1e178c6692d5c87a58f60a4bb0e4bfc325f82eb8165c86f04182ee0042f61bd7c417305d71abcd5e0c2ddeb9871401f", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286c10491608324e5626a0f18e860d4ccc4c85e634bc5c0c390c2bfbe", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286418a40578e442469311721e9049f62c63c78f0c10649cac4d41e31d0c7443091d53583a560aecaed102b817e88c653032a2f2ac590c4c1", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286bf049962c63c78f0c10649cac4d41e31d0c7443139e92ac15de5fa23c7bec590c4c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286bf049762c63c78f0c10649cac5a82d8c744316ac15d95da5fa23c7bec590c4c1", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286bf049162c63c78f0c1a999832c15c0b817aea9bfc7c2c590c4c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c304896251f7310f52e621ffc7c6c590c4c0", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_05.json b/http/http-client/src/test/resources/hpack-test-case/story_05.json new file mode 100644 index 0000000000..a760722587 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_05.json @@ -0,0 +1,386 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8286418d98a75c960cd32283212b9ec9bf847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff609a251147043745773468a1a9f168774355636f5f3e534fbf4370ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418df1e3c2e4b066991419095cf64d048960719ed4b08324a863c3c2c190c0bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286be048f6109f54150c10f6d49b0c542e4423fc3538e497ca582211f5f2c7cfdf6800b87c290c1739b9d29aee30c78f1e17258334c8a0c84ae7b2660719ed4b08324a863c1", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286c0048a63a21894f65234a17e88c553032a2f2ac490c3bfc2", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286c1048f63a218e9dad2d9e960aed2e25fa23fc6bec490c3bfc2", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286c104896251f7310f52e621ffc6539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc590c4c3", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286418f44e71d085c960cd32283212b9ec9bf84c8c7c690c5c1c4", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "8286c3048f6109f54150c12c19a6450642572211c8c2c690c573959d29aee30c22738e842e4b066991419095cf64cc7f60b2251147043745773468a1a9f168774355636f5f3e534fbf4370fda84a2290b2c540ea9a02d5f6a1288a42cb14f5c089ce3a11", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286c5048a63a21894f65234a17e88cac2c890c7bfbe", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "8286c5048b63a2189cf496b1cc55fa23cac2c890c7bfbe", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_06.json b/http/http-client/src/test/resources/hpack-test-case/story_06.json new file mode 100644 index 0000000000..47272301fe --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_06.json @@ -0,0 +1,362 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "828641862c63f4b90f4f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "82864189f1e3c2e58c7e9721e984c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418b2c63f4b2127b0c542e43d3049b63c56b10f524b5258b6ba0e3910c080113010b1910759c6d7e95cdc3539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc290c1738f9d29aee30c78f1e172c63f4b90f4b1", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286418ab0fdcb62e58c7e9721e9048862c3f72d88f55118c6c0c490c3bf60ffa3012c63f502ade04472aacdf544caade0fb524ac30475c72b0a89978000000000000036275c6c0d49ffe5a1ad8d982ecbf80bb0fe05f87643f3f2d89d71b03527ff9f6a11089a0238ebcf332842c8c036dc7dc68ae34e11c96518c238cbf6a220bd3437da86f5dd9452de9e7ef9b3aafcdeff7a60f3a0583c73dfc05ab7f307eefe60d34e817ed3fb3f3df867e74f0bbba6879f0cbfb6efdfc3c6adfc3cf3169eb9fa436e8dcd7bcfd300746e6bde7e90dba0ba7fdbb9707cfda951ea4150831ea82f4d0e1d10dd9f74945dd3a77c2de9df87a7316cb745e6bce7e982dd1bf6379fa68b745e6bcc3a0f0e4c353b8fa87a69e846b55fd34e8df83df3df767d3bf9b7a7a6da34f4d82e7eff69fda70cfa3961e9a365fcf0c387651bb5f1d1f8f5adfebdf3", + "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*" + } + ] + }, + { + "seqno": 4, + "wire": "8286418bad72c63f4848d2622e43d3048a607e18acc443085e634bc8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286be04b5607e18acc443149eb4302004514873c94150c633d06907e98bfb9963253372297ac418b596a9ad35516ea47451105b079640bd754dc8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286be049b607e18acc443135078c746328e42d8c4a3216339fab13044bcc697c8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286be049a607e18acc443135078c746328e42d8c27c19292d8c4c112f31a5c8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286be04a2607e18acc443135078c746328e42d8c1887aa2a4f19a82c53583f51043e42e2f31a5c8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286418f459e57a466a972c63f562695c87a7f048362c4d3c9c3c790c6c2", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_07.json b/http/http-client/src/test/resources/hpack-test-case/story_07.json new file mode 100644 index 0000000000..da019c3919 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_07.json @@ -0,0 +1,365 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8286418e4246931171f55e58c9254bd454ff049a62c45845eb9eb63b898f51b1631891a72e9f16e45b8685e634bf7abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c1539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176f518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff73929d29aee30c78f1e1794642c673f55c87a58f", + "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/" + } + ] + }, + { + "seqno": 1, + "wire": "8286c3049962c45845eb9eb63b898f5cd8b18b5e342cf5fc8dee615c8847c2538e497ca582211f5f2c7cfdf6800b87c190c0bf", + "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/" + } + ] + }, + { + "seqno": 2, + "wire": "8286c4049962c45845eb9eb63b898f5918b18ed0e9e3bd179b14b5ae4423c3bec190c0bf", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c4049a62c45845eb9eb63b898f4962c630fe8f466ed0ed9af38bd754dfc3c2c190c0bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c4049962c45845eb9eb63b898f5fac58c74a335f3fe05beb8f12fd11c353032a2f2ac290c1c0", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286c5049962c45845eb9eb63b898f5a98b188b46d1d95ce4bd93b2e4423c4bfc290c1c0", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286c5049962c45845eb9eb63b898f5ad8b18bdb7a9afdfe5be40dabf447c4bec290c1c0", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c5049a62c45845eb9eb63b898f5f8c79636767338671ecb39d8bd754dfc4c3c290c173ab9d29aee30c21234988b8faaf2c6492a5ea2a58b116117ae7ad8ee263d6462c63b43a78ef45e6c52d6b9108", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286c6049962c45845eb9eb63b898f5a58b18c03b23e478a9bfc165fa23fc5bfc390c2c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c6049962c45845eb9eb63b898f4eb1e587fa25d3f1930bbed95ebaa6c5c4c390c273ab9d29aee30c21234988b8faaf2c6492a5ea2a58b116117ae7ad8ee263d6a62c622d1b47657392f64ecb9108", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_08.json b/http/http-client/src/test/resources/hpack-test-case/story_08.json new file mode 100644 index 0000000000..2bb1f24e19 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_08.json @@ -0,0 +1,383 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864188968313ad8b90f4ff847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418bf1e3c2f2d06275b1721e9f84c2c1c090bf60a9bbf9011f7ec73a56f3e376a3fc47033f0883b35f6a50720e837b1a4c7aa02d4b5a8559bb6a1566eda8", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418fb50b8e4416cee5b17f439ce75c87a704022f61c453032a2f2ac390c273919d29aee30c78f1e17968313ad8b90f4b1f60e5bb03548aced6b6f3e36c0efc47033f08803dfed4eb177320c9803f6a68dd7a04c0165b0bed3ac841f9f6a5ec704335dd946dd93437fc5fc90c31dfdd0c38acc93437ebb724309ec3430e7d1b268614032430bb7af430e50689a1ba767ed4b488823a868801", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286c3049b60d48e62a1844e3b0ab2673216310f5216457619255ebaa65fbb9fc7539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc690c5c3c0", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c4049460d48e62a18968313ad8b22bb0c92af5d532fddac8bec690c5c0c3", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286c4048d625a0750e888bdcb52579aa2ffc8bec690c560c1bbf9011f7ec73a56f3e376a3fc47033f0883b35f6a50720e837b1a4c7aa02d4b5a8559bb6a1566eda8fb53d781c958400005b702cbef38ebf005f6dc79d6db683fc1", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286418ff4b8ea1d1e9262217f439ce75c87a70486625ac8bd747fcac3c890c7c2c1", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "82864188917f46a665c87a7f049a60856107b6b6107b6b8a62d45b0692c914b60e6a4b52579aa2ffcbc4c990c8c3", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286418998a75fd0e739d721e904022f62ccc2ca90c9c4c3", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "8286c8049662b9ce93a18a868190f4d27a90c34fb407c2cb2d098fcccbca90c960ff8c01bbf9011f7ec73a56f3e376a3fc47033f0883b35f6a50720e837b1a4c7aa02d4b5a8559bb6a1566eda8fb53d781c958400005b702cbef38ebf005f6dc79d6db683f6a4b445de041ed9ebfb525ac81000016dc0b2fbce3afc1b3bf709baf28bfe0f8761fba3d6818ffe4a82a0200002db8165f79c75f83fe0f8761fba3d6818ffe6cefdc26ebca2ff92f7320200002db8165f79c75f83f7a04f263dbe32efd3772efcb8b2efcb8a4664673d3fa81f2d3610cdf48c40a3475e74c97c1e747be1e756fe1e345f2072d391fcbbf2e21f26fafefe4f2904f84979baa3a7841ff1ed0179d0f3e78c1ff1ed0179d0f3e78c1ff1ed0179d0f3e78c1ff1eff8f680bce879f3c60ff8f680bce879f3c60c5", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_09.json b/http/http-client/src/test/resources/hpack-test-case/story_09.json new file mode 100644 index 0000000000..30985d9194 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_09.json @@ -0,0 +1,365 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864189a0d5752c86a9721e9f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418cf1e3c2f41aaea590d52e43d384c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418d42e45e8abac8bd0624952e43d304906104910c10f510696087a693d4c7447fc353032a2f2ac290c173929d29aee30c78f1e17a0d5752c86a9721e963", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c004906104910c10f510696087a693d4c1108fc5538e497ca582211f5f2c7cfdf6800b87c490c3bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c104906104910c10f510696087a693d4c7447fc6c0c490c3bf", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286c104906104910c10f510696087a693d4c1108fc6bec490c3bf", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286c104906104910c10f510696087a693d4c1108fc6bec490c3bf", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c104906104910c10f510696087a693d4c7447fc6c0c490c3bf", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286c2049160750e8f493110c5471da99d360c9d4b67c6c5c490c3408cf2b585ed695092c8b783267f8bfcd19f1a535ed2f6b4a84fc060ff408c873f53160fe7bc02f88c6579a6c6dacf32591669b7c0b46524ab4a095991b79c699147fcfda9414f10ed4cf124fd4b541fce2ddbee70bf1f2c386bcf9e426e726c795dd3946cfe73da823bca29aff8b531f2aa8e59e53bb8a21736ba4b9f1ad8ee0596c2fb4f3417ee351b6404a1640fb2100df8dc6df8df76479f700571a96491c65b6c4e47fcfda997760ddbb26ad392fc1fc8fa0fcdc038079c640271c0b627df13a27ff9fb53b99064c1fcf7803f18bf9fb53f16cf916c97ef41783f", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "8286c304986104910c10f4d27a98b5835333128fb9887aa2eecae621ffc8c7c690c5c1", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_10.json b/http/http-client/src/test/resources/hpack-test-case/story_10.json new file mode 100644 index 0000000000..a997e22074 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_10.json @@ -0,0 +1,359 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864185a5152e43d3847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "82864189f1e3c2f4a2a5c87a7f84c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418a1c880af4a072217a8a9f049062834760ecf4c5761a92c9521798d2ffc3539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc290c1738f9d29aee30c78f1e17a5152e43d2c7f", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286418c21e85d09e8ba16a5152e43d3048a62bb0d4964a90bcc697fc6c0c490c3bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286418c8e8b574248ba16a5152e43d30494606863c146cb0660b52d6a18a07e1865f5e634bfc7c1c590c4c0", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286bf048a62bb0d4964a90bcc697fc7c1c590c4c0", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286418c21e85d0922e85a9454b90f4f0495623b1841183312cac0e424e7310a88a634a25e634bc8c2c690c5c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286418d21e85d098c005d0b528a9721e9049c60cc3c061b66f4379c8420bae09a79c7857b08841ba26a17c4bcc697c9c3c790c6c2", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286418d21e85d098c015d0b528a9721e9049e60cc600310b9799089c65bc18410b2db6e38f5e7840c175b65a657e95cdfcac4c890c7c3", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286bf04a060cc5dbac5d0e1702fc2186fb57da86172e81c69ebb7eeddbd7f060bebf4ae6fcac4c890c7c3", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_11.json b/http/http-client/src/test/resources/hpack-test-case/story_11.json new file mode 100644 index 0000000000..9adaed83cf --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_11.json @@ -0,0 +1,389 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864188abd24d4950b90f4f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418b4af59cd526c3d142e43d3f048d6359cd52769e8a18df60c9d58fc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c0739f9d29aee30c78f1e178e322e43af6f562a2f84311da8354542161002ebc000360aad7b63b60c1eff6492d9e6edf6a6bdb31e0bb76ec30e1d1543f6a6bda93357afbeeb781a72f4382182eff", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286c1048d6359cd52769e8a18df60c9d58fc5c0c390c2bfbe", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286418f9ac1d739888797abd24d4950b90f4f04b062b193a8e62a182210c536d09352590c3623b6a9282a18aec3f42912860400898c7af39bb96f9631a4b8682f95c8847fc6538e497ca582211f5f2c7cfdf6800b87c590c473919d29aee30c78f1e17abd24d4950b90f4b1609cdba325f8000765004001082e38069d8ca57c00147f6a0e4f24440b7f", + "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=-" + } + ] + }, + { + "seqno": 4, + "wire": "8286c104a663a2181d75b043d349ea61141a42a273f860b4c659242c9ba8348544e7f176d351216c5fa23fc953032a2f2ac890c7c0bf", + "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=-" + } + ] + }, + { + "seqno": 5, + "wire": "8286c204a5608843005c2c209614b5308a0d215139fc3149e4b682a18450690d54d8874505b3d2e4423fcac1c890c7c0bf", + "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=-" + } + ] + }, + { + "seqno": 6, + "wire": "8286c204ae60727960d48e62a1886fee6190b0d38c0e45d90b4e38f31a79ef8b45dd1164d78f5698b3e0c3be2d444842bf4ae6cac5c890c7c0bf", + "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=-" + } + ] + }, + { + "seqno": 7, + "wire": "8286c204af62b193a8e62a18e88629b6849a92c861b11db5494150c5761fa148943020044c63d79cddcb7cb18d25c3417cafd11fcabec890c7c0bf", + "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=-" + } + ] + }, + { + "seqno": 8, + "wire": "8286c204b162b193a8e62a18e88629b6849a92c861b120d236309a8a7726c357aec3d27604008a22d05224c7aa294d45284d86ad7e88cabec890c7c0bf", + "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=-" + } + ] + }, + { + "seqno": 9, + "wire": "8286c204a962b193a8e62a18e8860b4148931ea43020044c4858c692a18ee690a7426c356c4a6a29426c356b9108cac1c890c7c0bf", + "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=-" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_12.json b/http/http-client/src/test/resources/hpack-test-case/story_12.json new file mode 100644 index 0000000000..6e6349c1d3 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_12.json @@ -0,0 +1,389 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864189acd524b615095c87a7847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "82864194a4b2186b10649cab50902f59aa496c2a12b90f4f049f62dae838e4602e34c842079c65d699132eb218afcffbba5c929228d7e95cdfc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c0738f9d29aee30c566a925b0a84ae43d2c760ff0a8ab35492d8542624150883f92e5f59f455bb47a9a7c9b8cdb24ab068f5da63bf828d7e860d01e92787d8dc04f37bbfa279d29978697b7fe02f93a89e85fcb677d9ad39f8f1cc06939d0de844bf9a1f1fb05e671e6312bcda58cbef70d8f566cb33191e3369e6ce8374dd97de8b323da039b4b11e9bfbf786cd8703dc3d329d9c21a59c1d6f43041fcf", + "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==\"" + } + ] + }, + { + "seqno": 2, + "wire": "8286c1049f62dae838e4602e05c65d03ad01f75b79979b6e2dda7a5fdba331628d7e95cdc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 3, + "wire": "8286c1049f62dae838e4604eb2dbecbad3807990084e09a8b0de3e0ebf88bd146bf4ae6fc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 4, + "wire": "8286c1049e62dae838e461b13e175971a65a13cfb2e38cc5d93ae9cb375f3146bf4ae6c5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 5, + "wire": "8286c1049f62dae838e4602171f6c4f882db4d0196df00a2cdeb7f2355ee98a35fa5737fc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 6, + "wire": "8286c1049f62dae838e4604f32d34db2e804e3aebad09b1450a5377471977c51afd2b9bfc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 7, + "wire": "8286c1049f62dae838e4604cba1684eb2e36fbe0136f09d8ad96fe0c726d2c51afd2b9bfc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 8, + "wire": "8286c1049f62dae838e46042682fb4f3ceb8e3edb2cb2f062e1769338dbf3451afd2b9bfc5c0c390c2bfbe", + "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==\"" + } + ] + }, + { + "seqno": 9, + "wire": "8286c1049e62dae838e4604eb416dc71f700cb8d3afbe07628425f73548e9146bf4ae6c5c0c390c2bfbe", + "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==\"" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_13.json b/http/http-client/src/test/resources/hpack-test-case/story_13.json new file mode 100644 index 0000000000..1b768e42de --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_13.json @@ -0,0 +1,362 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864185edd9721e9f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418aa4690af324d4ccb90f4f049763c78f0c1a91cc5431dbb080113129e8a0fe292af5d537c2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c0738e9d29aee30c78f1e17edd9721e963", + "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/" + } + ] + }, + { + "seqno": 2, + "wire": "8286c0049763c78f0c1a91cc5431dbb080113083a0f41e63af5d537fc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c0049e63c78f0c1a91cc5431dbb0801131295093771d0c4830bc828ec24ebd754dc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c004a063c78f0c1a91cc5431dbb0801131295093771d0c4830bd19e4f51cc06d7aea9bc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286c0049a63c78f0c1a91cc5431dbb080113141e63543a28882b897aea9bfc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286c0049c63c78f0c1a91cc5431dbb080113033751d59ce390d54c15c2bcc697fc4bfc290c1be", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c0049263a1fa958cc71d036364a34242b8170afd11c453032a2f2ac390c2bf", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286c1049863c78f0c1a91cc5431dbb080113149e33505d25f085ebaa6c5c0c390c2bf", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286418a35330579926a665c87a7049b63bb159888627ee1604d058085d602179c61d742d3ee89c5fa5737c6c1c490c3c0", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_14.json b/http/http-client/src/test/resources/hpack-test-case/story_14.json new file mode 100644 index 0000000000..5e84a4674e --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_14.json @@ -0,0 +1,359 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8286418841aa1ae43d2b92af847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418bf1e3c2e835435c87a5725584c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418ca8be10ba0d50d721e95c957f049763a21879d604008820134c0801105ebc7aa5de7ad7e88fc353032a2f2ac290c173919d29aee30c78f1e1741aa1ae43d2b92a63", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286418f35495e4ace7a1741aa1ae43d2b92af049060d5d073f5b6b60d5d073f5b6b5eb9ebc6c0c490c3bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "82864189332ba0d50cd4ccb92a04a163b9a429d8100226021032c7075e037ac2e3b7f788011042064410bcdb2bf4ae6fc7539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc690c5c1", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286bf049f6273d256040089808402638380683ad905fde200441080411082d38bf4ae6fc8bec690c5c1", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286bf04986273d25624290ec08007d8032c818a0f31e29cf495798d2fc8bec690c5c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286418a902ba0d50d721e95c95704986113cec50524e3a98100220802e20d50d8a0f31c2bf4ae6fc9bfc790c6c2", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "82864189301741aa19a999725504a06273d25604008980840cb1c1e6db0eb6417f7880110420640e32eb2d2fd2b9bfcac0c890c7c3", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "82864189305741aa19a9997255049f6273d25604008980840163838e34f6b6417f7880110420085a0b4c897e95cdcbc1c990c8c4", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_15.json b/http/http-client/src/test/resources/hpack-test-case/story_15.json new file mode 100644 index 0000000000..cade9e4ba0 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_15.json @@ -0,0 +1,356 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8286418748cf18ceb90f4f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418af1e3c2e919e319d721e984c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286be048d60d5485f314d41e31d0bd73d7fc2c1c090bf", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "828641871ae98c9254b92a049362b625ad8100211b03420a94308ac642af31a5c3539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc290c1739c9d29aee30c78f1e1748cf18ceb90f4b06aa42f98a6a0f18e85eb9ebf", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286c084c5538e497ca582211f5f2c7cfdf6800b87c490c3bf", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286c1048a62b625ad8100219fab1fc6bec490c3bf", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286c184c653032a2f2ac590c4c0", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "8286c2049b62b625ad810020231d10c4b5ad21ac2912b5761e93ad49aa5fa23fc7bec590c4c0", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286418d3533002ba4678c6724952e43d3049c6135a183058de197b7317e1a897f3f073a38cc458200016680bf4ae6c8c2c690c5c1", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "8286be049e6135a183058de1b3f4de3f264cbf9f9f9f9f9f9f9f8b0420582cb6bd754dc8c2c690c5c1", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_16.json b/http/http-client/src/test/resources/hpack-test-case/story_16.json new file mode 100644 index 0000000000..af79db78f7 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_16.json @@ -0,0 +1,395 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8286418c2d4bf8375356590c35cf64df847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff60ff3d216a4d83a2a3a4c42c51da4ea54c01fb5094189d5360c9d4d54cb20a8418f5405cbd4ee64370260a5c7cb3ec9463ebb28cb29b3fa7e8dd3e9d7f6a52590c3e46ea65ed416c5e3b49d4a955984be52b8ec4989417094b246327559360c9d4d54d0040ab30a6c193afda9496430f91ba997b505b17349060d0f33d11d07db5fbc9a33f8bbbcd9b0b23ce636fcc5f052fbfb5292c861f237532f6a0b62f1da4ea54aacc25f295c7624c4a0b84a5923193aac7ad263d4881e55985139fc7", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286c3048b63c1ba998d0335516b1cc5c2c1c090bfbe", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418d8cc942fe0dd4d496430d73d937049360b52fe0dd4d596430d73d933141c722f5cf5fc3538e497ca582211f5f2c7cfdf6800b87c290c1739c9d29aee30c16a5fc1ba9ab2c861ae7b2663c1ba998d0335516b1cc5f6896e4593e94642a6a225410022502edc6c5700d298b46ff", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286c1049360b52fe0dd4d596430d73d933141c722f5cf5fc6c0c490c3bf6896df3dbf4a002a693f75040089403f71966e09d53168df", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286c2049360b52fe0dd4d596430d73d933141c722f5cf5fc753032a2f2ac690c5c16896dc34fd280654d27eea0801128115c6d9b82754c5a37f", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286c4049360b52fe0dd4d596430d73d933141c722f5cf5fc9bfc790c6c2c1", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286c4049360b52fe0dd4d596430d73d933141c722f5cf5fc9bfc790c6c2c0", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "8286418fb6ba0e3917f06ea6a4b2186b9ec9bf049e63c1ba9ab2c861b05a9823041b198752673583ee388961ebacb22f5d537fca539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc990c8c46896c361be940094d27eea0801128266e34e5c6df53168df699713cf4724629646cad8da95d13a295b7a524607991ba50f", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286c104cf63c1ba9ab2c861b043d349ea43099eda636246241317c7510d54d14c6b28887d07524712a278961ebacb22a27d7e95ccc3a2afcad7c7510d54d14c6b28887d07524712a278961ebacb22a27d7e95cdcdc0cb90cac66896df697e94640a6a225410022502edc65db816d4c5a37f699770af48db924afc6565b69f6a36a47e50146e88b2046c97", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "8286ca049360b52fe0dd4d596430d73d933141c722f5cf5fcfc5cd90ccc8c4", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_17.json b/http/http-client/src/test/resources/hpack-test-case/story_17.json new file mode 100644 index 0000000000..02ee461a6b --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_17.json @@ -0,0 +1,368 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864188f439ce75c875fa57847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff6092bb03ae7403e30bcf8dc9daf88e067e110023", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84c3c2c190c0bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "82864187eabfa35332fd2b049960d48e62a1849eb61158982516301609458b0441009b5c8847c4538e497ca582211f5f2c7cfdf6800b87c390c273929d29aee30c78f1e17f439ce75c875fa56c7f", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c0049060d48e62a1849eb6115b141e63af31a5c6539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc590c4bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c104ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f351057e95cdc7bec590c4bf", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286418df5d07e48bfa1ce73ae43afd2bf048260e6c853032a2f2ac790c6c1c5", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286c304a260d48e62a18f051a672d8c4c5a8b60e861360ea4563b0b52624304a0f6c885e634bfc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c304a060d48e62a18f051a672d8c4c5a8b60e861360ea4563b0b52624308b6a5e634bfc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286c304ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f351097e95cdc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c304af60d48e62a18aec2d26b696087a925a928623aac604008986c1e5b03007c4f44849ec2c48b6b2d950d36d83a17e95cdc9c0c790c6c1", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_18.json b/http/http-client/src/test/resources/hpack-test-case/story_18.json new file mode 100644 index 0000000000..a6b4b55e35 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_18.json @@ -0,0 +1,371 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864187f439ce75c87a7f847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "82864188917f46a665c87a7f04b062791824eed45f0861d8bc1eca246021033101d0022a86988b416b9c75262453444179f7893f4582f3ef127a17e95cdfc2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc190c073939d29aee30c0ed5fd0e739d721e963fcae0b51f", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "828641891dabfa1ce73ae43d3f84c5c4c390c26093bb03548aced6b6f3e36c0efc47033f08803dff", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286c20488629331ebc0d7e88fc653032a2f2ac590c4c1", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "8286418cf56997f439ce71d6642e43d304856087a633ffc8bfc690c5c2", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286419341496d855876ae6a6cf07b2893c1a42ae43d3f048860931968cd5314ffc9c4c790c6c3", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286419024e3b12bca6a87510abfa1ce73ae43d304a960d521365b496a4b015c0c2ade01f9e8760938ec4fdd83aa62c0dc8c1a91cc5fb41bd9600baff97defcac5c890c7c460c8bb03548aced6b6f3e36c0efc47033f08803dfed44150831ea89091d898926a4b00596c2fb4e89d6c2e03ed4eb177320c9803f6a576a278926a4b12123b1300596c2fb4e89f6c2e03", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "8286bf04a960d521365b496a4b015c0c2ade019ec91824e3b13f760ea98b0372306a47317ed06f65802ebfe5f7bfcbc6c990c8c5be", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286bf04a960d521365b496a4b015c0c0ed92d44907960938ec4fdd83aa62c0dc8c1a91cc5fb41bd9600baff97decbc6c990c8c5be", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "82864191252b8ed5fd0e739d73f72d89b6c2ae43d3048a63a2229681a620c4063fccc3ca90c9c6", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_19.json b/http/http-client/src/test/resources/hpack-test-case/story_19.json new file mode 100644 index 0000000000..e1fe530063 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_19.json @@ -0,0 +1,365 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864187f43aa42f95ecb7847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418bf1e3c2fe875485f2bd96ff84c2c1c090bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "8286418bf438d0bfa1d5217caf65bf04d06087b6a4b1c6af1133ef08a4eba9a00002fd9e87b3621b79b5e61129d72e82f3af50bde207784baad84b2fee48663c22cd09452ebd5ab5bee7aecd4630cb7f362d97833d17f8976697b14bc6f85d2bbfc3539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc290c173909d29aee30c78f1e17f43aa42f95ecb5860994c15fda9e875485f369a481c682069b65d742cb617da7da6c3", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "8286c104ce6087b6a4b1c6af11334ca97bc766800003f67a1ecd886de6d6e7aecd4630cb7f34f45fe25d9a5ec52f1be1746cc1d89aaa69fcc2253ae5d048f60e6fcfde53738663c22cd0e8d0e399097dde4cffc6c0c490c3bfbe", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "82864187f43aa42f95d09f049d6282cc762262bbf6bfab943b335d020595fc87e99ab36e8b04e75cc43fc7c6c590c4", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "8286be049663c78f0c05765b7d8f1e3c30663d0ea90be595ebaa6fc7c1c590c4c0", + "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/" + } + ] + }, + { + "seqno": 6, + "wire": "8286be04906293d920d6a0f31d833141e63af5d537c7c1c590c4c0", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "82864189a48bfa1d5217caf65b048a63c0d249d874426da6ffc8c2c690c5c1c0", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "8286bf04a563c78f0c05765b7d8f1e3c3158e62a1690a8ea93d6c78f1e162210c45e3c78588842e4423fc8538e497ca582211f5f2c7cfdf6800b87c790c6c2", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c0049e63c78f0c44c4563b5d6b46b4f98f7e39bd62e7e8192eb3e28eb51d7aea9bc9c3c790c6c2", + "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/" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_20.json b/http/http-client/src/test/resources/hpack-test-case/story_20.json new file mode 100644 index 0000000000..0d7114ac6c --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_20.json @@ -0,0 +1,6002 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "82864188f439ce75c875fa57847abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c153b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177b518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ff6092bb03ae7403e30bcf8dc9daf88e067e110023", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84c3c2c190c0bf", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "82864187eabfa35332fd2b049960d48e62a1849eb61158982516301609458b0441009b5c8847c4538e497ca582211f5f2c7cfdf6800b87c390c273929d29aee30c78f1e17f439ce75c875fa56c7f", + "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/" + } + ] + }, + { + "seqno": 3, + "wire": "8286c0049060d48e62a1849eb6115b141e63af31a5c6539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc590c4bf", + "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/" + } + ] + }, + { + "seqno": 4, + "wire": "8286c104ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f351057e95cdc7bec590c4bf", + "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/" + } + ] + }, + { + "seqno": 5, + "wire": "8286418df5d07e48bfa1ce73ae43afd2bf048260e6c853032a2f2ac790c6c1c5", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "8286c304a260d48e62a18f051a672d8c4c5a8b60e861360ea4563b0b52624304a0f6c885e634bfc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 7, + "wire": "8286c304a060d48e62a18f051a672d8c4c5a8b60e861360ea4563b0b52624308b6a5e634bfc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 8, + "wire": "8286c304ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f351097e95cdc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 9, + "wire": "8286c304af60d48e62a18aec2d26b696087a925a928623aac604008986c1e5b03007c4f44849ec2c48b6b2d950d36d83a17e95cdc9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 10, + "wire": "8286c304ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f35132bf4ae6c9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 11, + "wire": "8286c304ad60d48e62a188ce7ea849ec2b043d349ea611594861d0c08011300784fc406d88c75545b1879af2f35136bf4ae6c9c0c790c6c1", + "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/" + } + ] + }, + { + "seqno": 12, + "wire": "828641881997f46a665fa57f04a862393bb0d80006c4c040f01e7da60400882013ec525b68f6dd9d6aa4f1a7a4bda9f5ede586bcc697cac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 13, + "wire": "8286c0048260e6cabfc890c7c2c6", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "8286be04a762393bb0e81b038c040f08407d8100220804d312cb4f837893d46797c7a44a9f350c2b0d798d2fcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 15, + "wire": "8286be049d62393bb1e8739cec741f71a0961ab4b1ea51c5dcc8b474371263ad7e88cabfc890c7c2", + "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/" + } + ] + }, + { + "seqno": 16, + "wire": "8286c5049963a0fb8d04b0d5a5896b8a31a0b14724530e26d702ed097e88cabfc890c7c2c6", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "8286be04a262393bb1e8739cec741f71a0961ab4b0441181000e01e134c5068c478e58a3717e88cabfc890c7c2", + "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/" + } + ] + }, + { + "seqno": 18, + "wire": "8286c4049960d48e62a1849eb6115898aec6131c51ccb04400840bd754dfcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 19, + "wire": "8286c4049e60d48e62a1849eb6115898b679189cf496b1cc58a399608801132bd754dfcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 20, + "wire": "8286c4049560d48e62a1841887a90c4673f5424f6142e2f31a5fcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 21, + "wire": "8286c4049260d48e62a1841887a90c527ee6285c5e634bcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 22, + "wire": "8286c4049260d48e62a1841887a90c4c3a4a171798d2ffcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 23, + "wire": "8286c4049b60d48e62a1849eb6115898253531598910e8a1608820034bd754dfcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 24, + "wire": "8286c4049460d48e62a1841887a90c4a7b136d450b8bcc697fcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 25, + "wire": "8286c4049a60d48e62a1849eb61158982d333121903424b64494d025ebaa6fcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 26, + "wire": "8286c4049c60d48e62a18ee690a75927acc44316148c04410b006622802bf4ae6fcac1c890c7c2", + "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/" + } + ] + }, + { + "seqno": 27, + "wire": "8286c4049960d48e62a1849eb61158982516301609458b0441009b5ebaa6cac1c890c773a59d29aee30c755fd1a9997e95b06a473150c24f5b08ac4c128b180b04a2c58220804dae4423", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "8286c5049b60d48e62a1849eb61158982535b043d35c43a285822080225ebaa6cbc2c990c8c3", + "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/" + } + ] + }, + { + "seqno": 29, + "wire": "8286c5049c60d48e62a1849eb611589845674d069a74b020042c040c84ebf4ae6fcbc2c990c8c3", + "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/" + } + ] + }, + { + "seqno": 30, + "wire": "8286418ba8be10b917f46a665fa57f04a360d48e62a1849eb3110c08011042065600000005f6564573ac000164cf6d31afd2b9bfccc3ca90c9c4", + "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/" + } + ] + }, + { + "seqno": 31, + "wire": "8286c004a662393bb02132eb0103c0659030200441081962399c41dd447313b16a23f5fa73cf5586bf4ae6ccc3ca90c9c4", + "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/" + } + ] + }, + { + "seqno": 32, + "wire": "8286c704896251f7310f52e621ffcccbca90c9c8", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "8286c0049660d48e62a1841496d864fa62b958f5d10525b6157e88ccc1ca90c973ae9d29aee30c483351eaa2f842fe8739ceb90ebf4ad8948c22b3d8943151abacf54482d862a18ff02cb617d965a7da", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "8286c3048a63a218f5d07e48bf447fcdc2cb90cabec9", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "828641909066a3d545f085fd0e739d721d7e95ff04926252308acf6250c546aeb3d5120b618a863fcecdcc90cbc660e3bb03ae7403e30bcf8dc9daf88e067e110023fb539e5dfab5e4bdbb0dddb821bf049074b77da867465921725875e6d9533a32fa3f2efd778f9b9905b6a9b59b8e6c0cddd1dde870fe2f79adfa2605a9f1a22b7f268919aa77d0bd5fe3873605be3bc01f", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "8286bf048b625231d10c4b1c55917e88cfc4cd90ccc0be", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "8286c304a862393bb0e85c13ec040eb2e05e60400882013ec7aafc93d7a2f524565b3faae4323b5ab0d7e95cdfcfc6cd90ccc0", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "8286418732fe8d4ccbf4af048e60d48e62a18a8be10c4a45e634bfd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "8286be049060d48e62a18310f5315ce749d798d2ffd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "8286be048e60d48e62a18a6762a2f842f31a5fd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "8286c404a562393bb0c818081d744d098100220804fb06f3199145affa989efcfb93acb5569586bf4ae6d0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "8286be04a160d48e62a18a8be10c4a3216339fab1517c222c23216339fac4eb9e5d717aea9bfd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "8286be049360d48e62a18b0759a4602bb6b818b684afd11fd0c5ce90cdc1", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "8286be048c60d48e62a18a8be04bcc697fd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "8286be049d60d48e62a1849eb3110c78375331515093d662222310f544d017aea9bfd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "8286c4049b62393bb1e8739cec741f71a0961ab4b1ea51c5dcc8b47436bf447fd0c5ce90cdc1", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "8286c404a662393bb017d96020744213ac0801104027d8b7d7bf1d6b2f9e88f7e8c2f73112d56b0d798d2fd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "8286c404a662393bb027db7d8081e6c2275810022084026241d1dfbbf5bf2f87d361a31f81f82ac35e634bd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "8286c404a762393bb027db7d8081e6c226981002208402623f6fd9ee6aac2d3ea41f98eb68d3c6b0d798d2ffd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "8286be04a460d48e62a1849eb3110c78375330590c93d8c24f598888abb22a0d5753533454097aea9bd0c7ce90cdc1", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "8286418aa2b4ae45fd1a9997e95f04c060d4c4834d336cbb4e46417f73f3f22fe97157ca875bd8b2cb791000b7a0be05bb3e06074c8c08011042065600000036d09640ea4567580002ddcc5f0bf4ae6fd1c8cf90cec2", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "8286418a1d322e45fd1a9997e95f04cc60d4c4834d363b68c1d33f89bdebf5671bfd7f5f3e9d754cb2cb791000b7a0b2cadd9f0303a64604008820642b0000036f09e5bd748887b2b4d85aa4580002cd85c740d002b77317c2fd2b9bd2c9d090cfc3", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "8286be04cc60d4c4834d359a2fe767f6babb55e3435fa1c3cfbcff82d8b2cb791000b7a0b2cadd9f0303a646040088210056000006de640b7ae9110f6569b0b548b000059b0bad85a0016ee62f85fa5737d2c9d090cfc3", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "8286c0049860d48e62a1849eb3110c110860d4d67b131772d825c8847fd2cbd090cfc3", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "8286c004a960d48e62a1821e9a4b610ac7443141a3431d3b5a5b3d3043d85602bb4b898e9dad2d9e97a4d52fd11fd2c7d090cfc3", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "8286c6049f63d5a663a56c5b3c8c1e8f54d6623015c0b8983533316cf25e9eaeabd754dfd2c9d090cfc3", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "8286c004a060d48e62a18a8be10c770b1eaa8a6a87dcd122bb0c92c42004407c4e2f5d537fd2c9d090cf73ad9d29aee30c197f46a665fa56c1a91cc543093d6622182210c1a9acf6262ee5b04b9108ff241a4b00801104027f", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "8286c9048260e6d3c8d190d0c4cf", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "8286c9048260e6d3c8d190d0c4cf", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "8286c1049660d48e62a1849eb3110c20e430e86234d5a3caf5d537d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "8286c1049f60d48e62a1849eb3110c78375331e927acc44448aec324b11887a90bd754dfd3cad190d0be", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "8286c104a360d48e62a1849eb3110c78375331e927acc44448aec324b14632759ac3db54885ebaa6d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "8286c1049860d48e62a1849eb3110c783753316168de38f39654af31a5d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "8286c1049960d48e62a1849eb3110c783753316168de38f69a69d2bcc697d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "8286c1049960d48e62a1849eb3110c783753311db45054c5419095e634bfd3cad190d0be", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "8286c7049963d5a663a56c5b2a580ae05c0c1a9998b532de9eaeabd754dfd3cad190d0c4", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "8286c1049b60d48e62a1849eb3110c783753303210f6d49de64d05bb32f5d537d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "8286c1049c60d48e62a1849eb3110c20e430e86115d864962310fbaa405c5ebaa6d3cad190d0be", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "8286c1049a60d48e62a1849eb3110c783753309b0b549bcc9a0b7665ebaa6fd3cad190d0be", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "8286c704a262393bb1e8739cec741f71a0961ab4b0441181000e01e134c5068c478e58a3697e88d3c8d190d0c4", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "828641881cebfa35332fd2bf04a862393bb0171a65b698081e680eb6c0801104200b0d4a51a25efeda7488f243fa928ef42c35fa5737d4cbd290d1c5", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "8286418eae81a653d94ae9f064a4b62e43d3048863c1a498a942fd11d5cad390d2c660ff4cacd241dd9b8165b0bed3ac81c69d75c71a642e080e01b6bed4eb0040bb2dae1005708995c2cb617da75b65c089f7de7fed49ad2a1311a483b8556610b2d85f69d6d971b79a7c2dbacfda91456a691c0d32f32f32e3cb882d0190b6d81b5c2cb617da75b684b8596c2fb4eb6d0970b2d85f69d6da12e1fb5228ad4d31c0d32f32f32e3cb89708170b2d85f69d6da17da91456a69f7034cbccbccb8f2e165b0bed3adb425c2b857b534911641fd486b0a44ff7ff2d4d2425507f521ac2913fdffcb534929920feaa3d45feff", + "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)" + } + ] + }, + { + "seqno": 73, + "wire": "8286bf049b63c1a498a94309f052a628ed4a4f52e165b0bcd3cf3825e74d347fd6d5d490d3c7be", + "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)" + } + ] + }, + { + "seqno": 74, + "wire": "8286418e21eaa8a44af28c858ce7eabd454f048a63a0e2cbad81d142fd11d7ccd590d4c8", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "828641958faa3a8eb32f20cd47aa8be10bfa1ce73ae43afd2b04856242a466a3d8cdd690d5c9c7", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "8286c1049c63c1a498a943129e8a0fe228ed4a4f52e165b0bcd3cf3825e74d347fd8d7d690d5c9c0", + "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)" + } + ] + }, + { + "seqno": 77, + "wire": "82864189ad74f832525b1721e90485612bcc697fd9d0d790d673ae9d29aee30c5740d329eca574f832525b1721e963c1a498a94309f052a628ed4a4f52e165b0bcd3cf3825e74d347fc2", + "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)" + } + ] + }, + { + "seqno": 78, + "wire": "8286418e24952e3accba7c19292d8b90f4ff048d602c5b65086087b6a4afd107abdbd0d990d8bfc3", + "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)" + } + ] + }, + { + "seqno": 79, + "wire": "82864188b174f835332e43d3048363a1d3dcd3da90d9c0", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "8286bf048d602c5a82d8861139fc2fd107abdcd1da90d973af9d29aee30c5740d329eca574f832525b1721e963c1a498a943129e8a0fe228ed4a4f52e165b0bcd3cf3825e74d347fc5", + "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)" + } + ] + }, + { + "seqno": 81, + "wire": "8286c204856255e634bfddd4db90dabec5", + "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)" + } + ] + }, + { + "seqno": 82, + "wire": "8286bf048363a1d3ddd4db90dabe", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "8386418c39115afdcb619069aa5c87a784dedddc90db0f0d82085b5f911d75d0620d263d4c1c88ad6b0bdad2a13f", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "8286cf04896251f7310f52e621ffdfd6dd90dcce", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "8286cd048e60d48e62a182210c7ae825c8847fdfd8dd90dc73ac9d29aee30c4e51c941aa2a17f439ce75c875fa56c4f47f83804008821032b0000001b684b207522b3ad18d05", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "8286ce048c60d48e62a1825051d8bcc697e0d7de90ddbe", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "8286ce049860d48e62a18a8be10c10f1d83aa435533081d48acebcc697e0d7de90ddbe", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "8286ce0497628346c545f0863a20f531d116444a0684441882bf447fe0d5de90ddbe", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "8286418f9ca3928354542fe8739ceb90ebf4af04032f686ce1e0df90ded2dd", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "8286cf04a2628346c545f08610721874683c96d0562c28e849a92ee28ec24f106202d49aa5fa23e1d6df90debf", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "8286cf049a628346c545f0863a76b4b67a63a76b4b67a5d25a6ba0692afd11e1d6df90debf", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "8286cf04a0628346c545f08610721874683c96d05625190b19cfd620c4cc415a9354bf447fe1d6df90debf", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "8286cd04c260d4c4834d377d3562682ec5f9fb970b7bd1975ceee1c3b16596f220016f417c0b767c0c0e9918100220840cac0000006da12c81d48aceb000059a5bb98be17e95cde1d8df90debf", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "8286d504a762393bb0e81b038c040f0841030200441009a6012ca4eed4964ef1ac03bd3bd87e96ac35e634bfe1d8df90debf", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "8286d504a762393bb0e85c13ec040f082f3ec0801104027d815414c9ecc491ee8e94e994be6332c35fa5737fe1d8df90debf", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "8286cf0494628346c545f0863a76b4b67a63a76b4b67a5fa23e1d6df90debf", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "8286cf0497628346c545f0863c1a498a9431e0d24c54a220c415fa23e1d6df90debf", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "8286d504a662393bb027db7d8081e6c22758100220840260d40fa0a2922f6789f8fa4c6abb27d2c35e634be1d8df90debf", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "8286d504a662393bb027db7d8081e6c22698100220840263bf71d111273a1917589d3f5313abeb0d798d2fe1d8df90debf", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "8286d504a562393bb0c818081d1059698100220804fb1dbb8891513f48ec183b58dd686dbf0b0d7e95cde1d8df90debf", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "8286cf049960d48e62a18a8be10c770b044218a468496c5aa2f842e4423fe1dadf90debf", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "8286d7048260e6e1d6df90debfdd", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "8286cf049a60d48e62a18a8be10c770b1517c22241c861d11da949ea5e634be1d8df90de73a89d29aee30c197f46a665fa56c1a91cc5431517c218ee1608843148d092d8b545f085c8847f9dc21f", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "8286d0049c60d48e62a18a4b2186c7aa6d3306a666283545e4690b135e42bcc697e2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "8286d0049960d48e62a18a8be10c770b1eaa8915d864962310f5217aea9be2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "8286d0049a60d48e62a18a4b2186c7aa6d3306a666083b2cb0e9884bd754dfe2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "8286d0049e60d48e62a18a4b2186c7aa6d3306a6662b9ce93e92f889a6fc85b5e634bfe2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "8286d0049d60d48e62a18a8be10c770b08aec324b14736ddfb8a3b093dd3f95ebaa6e2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "8286d0049a60d48e62a18a8be10c770b08aec324b11887dfe0c9496c5ebaa6e2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "8286d0049d60d48e62a18a8be10c770b1eaa8915d8649628c64eb3587b6a917aea9be2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "8286d0049460d48e62a18a8be10c770b160eaea6aa65ebaa6fe2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "8286d0049a60d48e62a18a8be10c770b1eaa8a6a87dcd122bb0c92af5d537fe2d9e090dfbe", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "8286d8048260e6e2d7e090dfc0de", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "8286d0049063d5a663a56c5b42581d961fc2f31a5fe2d9e090dfc0", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "8286d004a060d48e62a18a0c849aa99849cf431eba0fc918f5d07e48b1a5b0749579d34d1fe2e1e090dfc0", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "82864194b0a3a126a4aba0a3b093afe8739ce3acc85fa57f048663b858ace84fe3d8e190e0c1", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "8286d10499628346c545f0863c1a498a94309f052a628ed4a4f52f3a69a3e3e2e190e0c1", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "8286d9048260e6e3d8e190e073ffbe039d29aee30c197f46a665fa56c1a91cc543141909355330939e863d741f9231eba0fc91634b60e92af3a69a3fc45840413a535aacc2a8b0aa2c3eba0fc917f439ce75c875fa56a8b09ccab3850ab37c751693a22a8be100089f6d51386559be203af3a07db65a544e78559bea89c1d732acdf0aa2712ab37fa2a272d559bf3a535aa26d98551362c2a89b1619ca3928354542fe8739ceb90ebf4ad51362c33d0a89b6708d5136cdf100220840cac0000006da12c81d48aceb46341551396165559bf3a535aa26d98551362c2a89b1619066a3d545f085fd0e739d721d7e95aa26c586522a26c585159ec4a151362c351abacf54482d862a151362c2a89b6708596c2fb2cb4fb4a89c2d44559bf8385e5b2eb544e22b190b924559bea89ce86479034012acdf544e27d565559bea89c2583f1470b28559bff08b0818274a6b55985516154587d741f922fe8739ceb90ebf4ad5161e8854587d741f922c6a925b2a1d0b463aaa2d8bf442ace135335b650ab37e74a6b544db30aa26c58551362c239d7f46a665fa56a89b161352398a8544d8b09a9544d8b09aaa8b60e4544d8b0aa270d4cd58d33aacdf8eab03121110626400584d817e95cca89c2506275b6ca1566fce94d6a89b661544d8b0aa26c586c917f439ce75c875fa56a89b1618fd9151362c28910a89b1617dd71a7951362c25ee9544db37df75c69e544d8b0fcce94d6a89b661544d8b0aa26c586832126aa65fd0e739d721d7e95aa26c587d455d87a4ea89b161a0c849aa9801544d8b0aa26d9c27544db37f2eb0b2d83fe0", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "8286c10486610461139fc7e4d9e290e1c2e0", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "8286ce04a862393bb0171a65b698081e03c26d810022084016273181eeab3cf7447e4122401eb14cb0d798d2ffe4dbe290e1c2", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "8286d20498628346c545f0863c1a498a94306a473150c27c14a95ebaa6e4dbe290e173ffcd029d29aee30c197f46a665fa56c5068d8a8be10c7834931528613e0a54c51da949ea5e74d347f9140165b0bed3e179f7197be087b6a4c151ea2fc1a4813e0c9496c893e0a54c51da949ea885f140ea9a0e83f83d8698d50e88ac2ca5b0b6413a535aacc2a8b0aa2c339472506a8a85fd0e739d721d7e95aa2c33d0ab3846ab37c4008821032b0000001b684b207522b3ad18d05f8b0b21ac291307c24be5302b81b56ebaac2f2b81a56ec2add855c0caaf0557af2b830ab76f2afb2ae06d5bafab75a57032abc156eb8ae0655784abd0ab81c55f75585b57038abf79586f2b81a56ebcabc05706156ede55e0ab81b56ee05617d5c0dab75e56e815c0caaf0558702b81f55f795bb855c0faaf32ac2f2b81955e0aaf5e57038add0ab76157036abd7557efab81c55e7d57d95706156ede55e795c0caaf095badab81955e655bacab81955e12b742ae0655784ac2d2b81955e12b75f57032abccaafdf57032abccab76f2b81955e65579a5706156ede55e7d510165440e7fc2b81955e6557aeab81955e65585b57032abccab76f2b81955e12b75ff8b6ca209d29ad56615458551619ca3928354542fe8739ceb90ebf4ad51619e8559c23559be200441081958000000db425903a9159d68c682ff", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "8286d3049b628346c545f0863c1a498a94306a473150c27c14a98ba0d7aea9bf7abcd07f66a281b0dae053fad0321aa49d13fda992a49685340c8a6adca7e28102ef7da9677b8171707f6a62293a9d810020004015309ac2ca7f2c05c5c1dd518b2d4b70ddf45abefb4005db90408721eaa8a4498f5788ea52d6b0e83772ffc1", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "8286d60499628346c545f0863c1a498a94309f052a628ed4a4f52f3a69a3c053b0497ca589d34d1f43aeba0c41a4c7a98f33a69a3fdf9a68fa1d75d0620d263d4c79a68fbed00177febe58f9fbed00177bc090bfc7", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "8286418caed9652d8b917f46a665fa5784c2539a352398ac5754df46a473158f9fbed00177bebe58f9fbed00176fc290c1c9", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "8286bf84c3bec290c1c9", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "8286bf84c3bec290c1c9", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "8286bf84c3bec290c1c9", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "828641881997f46a665fa57f049e60d48e62a18352c1a998d4b15904c1a9080010b4f8990564a6c0afd2b9bfc4bfc390c2c6", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "8286418eb6ca10b8eb32e9f064a4b62e43d3048d602c5b65086087b6a4afd107abc553032a2f2ac590c4c7d6", + "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)" + } + ] + }, + { + "seqno": 130, + "wire": "8286c284c6c1c590c4cc", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "8286cb04896251f7310f52e621ffc6c1c590c460ff71bb03ae7403e30bcf8dc9daf88e067e110023fb539e5d38396ebdab468c1a77c1240073d67c9e37b583a4b7b863d117ec3bf5efdf7978cae61f184bf96f98a2cc5e45ed45fccbc98fc66bfb39f69b2e1c7d1f5f1e5a34e2a77f8e53755e76a75d1c1ee316fbf2ed2598fc5fe99f95962331fceeb7c9b90f86b7b5f7c1c218f2f02bfe727575fce7e59ac71345fe9cb6f5f5778e78fb72ec9cb7621f9ddd47270d5f1de00fda9cf2e9c1cb761bb04904cd8a569b8dac1d0b97b7b1f571d734f5e3cedc32b98345f71cc3a3f724b4d7931322f5e27ad7fddbe5cc10caef7c57f3f4edd5d2ecc59a9c5377c2498ff1de00ff", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "8286cc04032f686cc7c4c690c5cdbe", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "8286c1048e60d48e62a1849493b1192a0afd11c7bfc690c5739f9d29aee30c4e51c941aa2a17f439ce75c875fa56c4f47f848293a4ff09828f", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "8286c204a762393bb0c844d30103acb4e898100220804fb14f5989e3da67a229e3aeaf3ea24d47586bcc697fc8c3c790c6be", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "8286c204a862393bb0e85c13ec040eb4d85d60400882013ec75ec77ac9a3b621faeb4f9f32b24ed2ac35e634bfc8c3c790c6be", + "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" + } + ] + }, + { + "seqno": 136, + "wire": "8286418732fe8d4ccbf4af049a60d48e62a18a4b2186c7aa6d3306a666083b2cb0e989b5ebaa6fc9c4c890c7cd", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "8286c304a662393bb027db7d8081e6c2275810022084026096203377afdd0eb511a8aa391ef542c35e634bc9c4c890c7bf", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "8286be04a660d48e62a18a8be10c47ea83545431dc400880fb148cd5311d56311d5644c801e5f02f5d537fc9c4c890c7bf", + "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" + } + ] + }, + { + "seqno": 139, + "wire": "8286418df5d07e48bfa1ce73ae43afd2bf048260e6cac2c990c8c06092bb03ae7403e30bcf8dc9daf88e067e110023", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "8286c0049b60d48e62a18a8be10c27c19292d8c27c448acf1320044e017e95cdcbc6ca90c9c1", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "8286c504a662393bb017d9602075a65a030200441009f62c9eab51dcd3f8ae67facf38eb7fbd4b0d7e95cdcbc6ca90c9c1", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "8286c504a762393bb0179c130103ccb8f8581002208190312f57bc7947bedea6a2b97c75191beb42c35e634bcbc6ca90c9c1", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "8286d004032f686ccbc8ca90c9c1c2", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "8286c504a762393bb0e85c13ec040f082f818100220804fb11799fcceddbd64eeca1c39a63b51f6586bcc697cbc6ca90c9739f9d29aee30c4e51c941aa2a17f439ce75c875fa56c4f47f848107213e13051f", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "8286c604a762393bb0e85c13ec040eb6f3c060400882013ec77427a953d6ceecca4345ee5e80963586bf4ae6ccc7cb90cabe", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "8286c604a662393bb0c818081d1080cb0200441009f62cf7dbaf99e91f5ead467eb6514bcec4b0d7e95cdfccc7cb90cabe", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "8286c0048260e6ccc4cb90cabebf", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "8286c1049e60d48e62a18a8be10c52792da0ac5320801101d03f14c828ec24ebf4ae6fccc7cb90cabe", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "8286419821ea496a4afe8c5a24a4750e62d8b96498a8b4c92af5153f04a760693d2861d0b12bcc4b1b052b0e8657a58ca591f70a219197a469c65e91c238511485697e95cdcdc8cc90cbbf", + "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" + } + ] + }, + { + "seqno": 150, + "wire": "8286d204032f686ccdcacc90cbbfc4", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "8286c704a762393bb0e85c13ec040eb2e05e60400882013ec26890ed52dce4b47d3c2687cb1d8eac35fa5737cdc8cc90cb739f9d29aee30c4e51c941aa2a17f439ce75c875fa56c4f47f848231a0bf09828f", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "8286c804a762393bb0cb61698081d03ceb6c0801104201312199b653516d5d3c3f6d0fd567a990b0d7e95cdfcec9cd90ccbe", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "8286c2048260e6cec6cd90ccbec1", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "8286418a1d322e45fd1a9997e95f04c160d4c4834d36edfb30eec5b9cbb15b476d9f97d7ebb6eaf32cb2de42d816f4f32b767c0c0e9918100220840cac00000071e756f47a560000b0564cf6d31afd2b9bcfcace90cdbf", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "8286c904a662393bb0c818081d101f6d8100220804fb1178f7ebdb32a3dcfdbb9ed2389b47dd61afd2b9bfcfcace90cdbf", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "8286c004a860693d28604cb00658942c3aeb02640cca175d7de94010b91b6f9246d99638db95e7de7595fa5737cfcace90cdbf", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "8286d404032f686ccfccce90cdbfc6", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "8286c904a862393bb0e85c13ec040eb4d85d60400882013ec76f54b688a5b4f575f12ced77f0e01e586bcc697fcfcace90cd739e9d29aee30c4e51c941aa2a17f439ce75c875fa56c4f47f8481159fe13051", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "8286ca04a962393bb0e85c13ec040eb2e05a60400882013ec78a91d633592f497a7aeddba78e95796561afd2b9bfd0cbcf90cebe", + "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" + } + ] + }, + { + "seqno": 160, + "wire": "8286c4048260e6d0c8cf90cebec3", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "8286ca04a762393bb027db7d8081e6c22698100220840261d097c5824cf44bda217a376f53f4f0b0d798d2ffd0cbcf90cebe", + "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" + } + ] + }, + { + "seqno": 162, + "wire": "8286ca04a662393bb0c818081d1040e30200441009f62727b30dff0e7bf6667a23afbabbf93ac35fa5737fd0cbcf90cebe", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "8286ca04a762393bb027000798081d75d138c0801104027d8f768e31cd44d223c1ab67c798a51f8586bf4ae6d0cbcf90cebe", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_21.json b/http/http-client/src/test/resources/hpack-test-case/story_21.json new file mode 100644 index 0000000000..f8032bc741 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_21.json @@ -0,0 +1,16154 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264016196dc34fd280654d27eea0801128166e01ab82714c5a37f7685dc5b3b96cf0f1f919d29aee30c78f1e171d23f67a9721e963f0f0d8213204088ea52d6b0e83772ff8c49a929ed4c02fa5291f98040408721eaa8a4498f5788cc52d6b4341bb97f5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "885f87352398ac5754df0f0d8371b75d7f0188ea52d6b0e83772ff6196df697e94132a6a225410022502edc6deb8d3aa62d1bfc45891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96c361be940bea6a225410022504cdc6dfb8dbca62d1bf55857d913ad03f4089f2b0e9f6b12558d27fadf139af453e9a6ecd66a69eccb61ee187b51879ad78d33812f9a247f67e4cfbfddadbe359dfebee5ed81fd9041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "885f87352398ac4c697f0f0d023433c76196e4593e94138a6e2d6a0801128215c0bd719754c5a37fcd6c96df697e94136a6e2d6a0801128205c139704153168dffc7c65585644d3efb607f05accf7a8b3af0a2c12cf9cb90fa7c6b5af79f38add14e5d935bbc34f1d384939ab4e9fcde29badb6611849e2083c4c3", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88cc0f0d8365d75acb6196df697e94640a6a225410022504cdc00ae34d298b46ffd1cac96c96df697e94640a6a225410022504cdc00ae34d298b46ff5585640fba067f7f02ac06eab164af0831d07365be9bbb91d6b067d64a2f6a93d2c4bb8eea35b39f7f092efa58140a7a79ede42f1041c8c7", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88d5d40f28ba4753550547475355f6a5634cf031f6a487a466aa05c748fd9ea5c87a7ed42f9acd615106e1a7e94032b693f7584008940b3700d5c138a62d1bff4085aec1cd48ff86a8eb10649cbf4088f2b0e9f6b1a4583f91063c0e6efd6f1b7fad73743ba16dacafff4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f95886a8eb10649cbf64022d314088f2b0e9f6b1a4585fb4d1da49b466f36871b92cdfad13f39b12e8d9ebcdee36d7c534c86859a77f620aa6bfdc63c70b0d68c3819be9e28bb8dcbad4f5ff7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab5f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88d00f0d023433d96196df697e940854dc5ad410022502cdc64371b0a98b46ffdfd8d76c96c361be940894dc5ad41000f28105c0b3719694c5a37f558669b75d6db73f7f0cad87bcc6fd4b9b3be2365e9c6b49aaf3a39211da4c0f0a1df6eef3402fad825d9dbacce1b8e8bb7a6cbd64d9041fd6d5", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88d40f0d8375e0b3dd6196c361be940094d27eea0801128076e001700153168dffe3dcdb6c96c361be940094d27eea0801128066e341b82654c5a37f5585081e138e7f7f02abbc0d6d1ab77d76d4823351b744fdd91bd5a7dd75e50c52496e0cee97f0ba28bd91079f00348e401af78820dad9408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "885f88352398ac74acb37f0f0d83136067e36196df697e9413ea693f7504008540b971a72e32f298b46fe96c96e4593e940094cb6d4a0801028176e36ddc6da53168dfe3e2558613ecb8271c7f7f04aededcf92ad51b93f0d5d9ad3bb9efe297b7f445edd8b6f0c63975f9f18baee6fa1b4e2f75e7a4de6ff0a795b34107e0df", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88de0f0d8375a683e76196c361be9413ca6e2d6a080112816ae36fdc13ca62d1bfed6c96df3dbf4a019532db52820040a0037001b8d054c5a37fe7e65585642065a7df7f02ad7abb7b55c3417d4e0c0fdfbd659d391efb69befe2e9da6c5eac707a3d4cb2ddb3a05ed382367664e8fe3d9041fe4e3", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88c60f0d83682277eb6196df3dbf4a09d53716b50400894106e34e5c680a62d1bff1eae96c96e4593e940894dc5ad410022504cdc69bb820298b46ff5586642e36d38eff7f02aecfa0f267cbd2edbc38338fa7307b1fa1c84dfc511517f5ecccb1f26667972e79687fd75db83dcba7252fe8f1041fe8e7", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88ca0f0d83642cb7ef6196dd6d5f4a05c53716b504008940b371a7ee32053168dff5eeed6c96df3dbf4a05953716b5040089403571a72e32d298b46f5586682d34d3eeff7f02ac7356144afd5aed5afb517ae5b3d328c9a7de91faf53392d2e09bcb2fef126ba7b739351884369019bb26820feceb", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88ce0f0d83640cbff36196dd6d5f4a01a5340ec5040089408ae34d5c036a62d1bf7685dc5b3b96cff3f20f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96c361be940094d03b1410022502f5c69cb80694c5a37f55861040f09e10bf7f03acb1df4cdf0344d9ebf7906be6dbf64f2e63f2bf6de7fd6396b6cb575941e9f1b97730f0c4e6b25fe333b34107f1f0", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88d30f0d83684217408721eaa8a4498f5788ea52d6b0e83772ff6196d07abe940b8a65b68504008940bb7001b8d3ca62d1bfc35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96d07abe941094cb6d4a08007d408ae005702053168dff55867da79f75b7ff7f05ace34ea2ce6b5ca6ff0bb5efc7ea8a4d555de426ef6eebf6cc7e218a4d26a1c3753b3db264cd6b55f7f1b268207caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88dc0f0d830ba10fc66196d07abe9413ca693f75040085400ae04171a0a98b46ffcbc5c46c97df3dbf4a05b5349fba82001d500d5c13771b6d4c5a37ff558613ed802e09cf7f04adf17e7e002d97bc0399fd6d9a1e941cde7c1bd27037924c3bd6b2f6f6f26ff1e75f96edc336287bb60e6fec820fc3c2", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "88e00f0d8365d107ca6196c361be940bca693f75040085410ae099b8c854c5a37fcfc9c86c96df697e94034a651d4a08010a817ae34f5c1014c5a37f558664027c4f36e77f02aee7f9a712d573d06c1c4c0987b7166b2f64974eabfafbe4cdab0379d693deb2fe7bf5ce70e7b766fcfd3bc9ba1820c7c6", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88e40f0d84134cb8ffce6196dc34fd280654d27eea0801128076e001700053168dffd3cdcc6c96dc34fd280654d27eea0801128066e34cdc684a62d1bf5584105e71df7f02ac10d0341fd13b17c5bd1bc3e2a73c394f4bddf56893f767ee7fd9f4cf250d35cfd1c2b4391f9f63b1e1966820cbca", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "885f87352398ac4c697f0f0d830882e7d36196dc34fd282794cb6d0a080112806ee01bb8dbaa62d1bfd8d2d16c96d07abe9413ca612c6a08010a817ae32e5c0894c5a37f558579a7db7c207f03ad72767536e484e9eb6323d1152d8de88d62dc66e3eefdea49e3d64e1f987773267c393664ddeba37b1a73bc3041d0cf", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88ed0f0d8469d75c77d76196c361be940bea6a225410022502d5c6c571a794c5a37fdcd6d56c96d07abe9403ca6a2254100225042b8c82e36da98b46ff5585089e7da7df7f02ad46a735f6be2f583b0f5d743783be9e75624579ad9ed87f11c59e92adcc61353c82279ddb9cfe3bf1d9bf64107fd4d3", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88f10f0d8369c0b3db6196dd6d5f4a09d5349fba820042a099b8d3571b1298b46fe0dad96c96d07abe941054d27eea08010a820dc6857196d4c5a37f558613ed840cbadf7f02adeddde69abffbe6dcf4755b3e2e815a1cba6be9ee2cfabde7da22624598c79f6d2ff4871a7a03d55adc724d9041d8d7", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "88f50f0d8365f65adf6195dc34fd282029a88950400894002e00371a0a98b46fe4dedd6c96c361be9413ca6e2d6a0801128166e320b8cbaa62d1bf5585089b71b71c7f02adcbc9bd9eade58af8db3757e1c9811769ab8b9cecf49d6fc2969eb13578e5d3375a9d76cfcd5d1e2797f943041fdcdb", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "885f88352398ac74acb37f0f0d830b2d35e46196dc34fd280654d27eea0801128005c6dfb8c814c5a37fe9e3e20f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96e4593e94134a6a225410022502f5c6c3700f298b46ff558469969f777f03adc99a8f3ca923d1fac78e2c39709a33f64df74327b0635b175ba3f4cee1e2139a3c68bdf92e79531639b9f8820fe1e0", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88ec6c96e4593e940b6a436cca0801128215c6c371b654c5a37f5f86497ca582211f7b8b84842d695b05443c86aa6f5a839bd9ab5893aed8e8313e94a47e561cc581c134c81d79d0ff6496d07abe940b8a436cca080c89403b71b6ee32f298b46f6196dc34fd280654d27eea0801128166e01ab82754c5a37f0f0d836d96daef", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88f36c96e4593e94642a6a225410022502cdc13771b0298b46ffc4c3c25893aed8e8313e94a47e561cc581c640d3827d917f6496df697e94138a6a22541019128166e32fdc6df53168dfc10f0d8365c6def2", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88f66c96df697e94132a6a225410022500f5c002e36ca98b46ffc7c6c55893aed8e8313e94a47e561cc581c13ef3c2780d7f6496df697e940bea6a22541019128205c643702153168dffc40f0d8375c645f5", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "885f87352398ac5754df0f0d8369e035f66196e4593e94642a6a2254100225041b8db3700ea98b46ff7685dc5b3b96cff6f56c96d07abe9413ea6a2254100225041b8105c034a62d1bff5585109d69e0ff7f11ac8e4f5c79cd2bb19f93e0eb3f07efbfd776c6ac4bd8da0cf17ab65add7fddfcf159c61786fc767b164f10c107f4f3", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88c30f0d03313438408721eaa8a4498f5788ea52d6b0e83772ff6197dd6d5f4a05b532db42820044a059b8dbb719654c5a37ffc35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96d07abe94005486d99410021504cdc64571b714c5a37f55857db79d105b7f05aec5ddc4e59daef978e1c9aaef9a11af9f38aa5a9b6bfde7abb23b022c9f98f7fb7396e79fedca1b3d6acde9e9a0837caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88cc0f0d03333536c66196c361be9413ca6e2d6a080112800dc699b8cbaa62d1bfcbc5c46c96df3dbf4a082a65b6850400854102e340b8dbea62d1bf5585642d844d877f04ac85a2e9f2d79bb0daf597f345bb774e325e3f33b6fd9908d8eee1ae70d45c65ecfba79f17af70e9d329e1820fc3c2408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88f40f0d8371f79ccb6196dd6d5f4a32053716b50400894082e36fdc69f53168dfd06c96df3dbf4a019532db52820040a003700e5c644a62d1bfcbca558513ed36075f7f03acbb7bdbd937f4a3070d352c9865295bc9b39eff189f1ca725314417345239f764bd497b75f4f269eeb7686083c8c7", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "886196dc34fd280654d27eea0801128166e01ab82794c5a37fd40f28ba4753550547475355f6a5634cf031f6a487a466aa05c748fd9ea5c87a7ed42f9acd615106e1a7e94032b693f7584008940b3700d5c138a62d1bff4085aec1cd48ff86a8eb10649cbf4088f2b0e9f6b1a4583f91063c0e6efd6f1b7fad73743ba16dacafff4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f95886a8eb10649cbf64022d314088f2b0e9f6b1a4585fb4d1da49b466f36871b92cdfad13f39b12e8d9ebcdee36d7c534c86859a77f620aa6bfdc63c70b0d68c3819be9e28bb8dcbad4f5ff7b9384842d695b05443c86aa6fae082d8b43316a4fe75f87497ca589d34d1f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f408cf2b0e9f752d617b5a5424d279a96591b132d32b09b8dc582128961902eacdbae3600b323aebedf5892a47e561cc5804f819034007d295db1d0627f0f0d83085a074084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03323936eecc", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88be0f0d836dd13dde6196e4593e940814d444a820044a00371966e09e53168dffe3dddc6c96dc34fd282129a88950400854002e340b8d814c5a37ff558379f0337f11ad3c9eeaddde1c9ea5eeee9a7b7efe39088fbf1e08b27e3764ef3cff7ba3d79a5f15cccc3a0eff567713f090c107dbda", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "885f8b497ca58e83ee3412c3569f0f0d8371f6c3d1e7", + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "6951" + }, + { + "date": "Sat, 03 Nov 2012 13:04:28 GMT" + }, + { + "server": "Server" + } + ] + }, + { + "seqno": 32, + "wire": "885f87352398ac4c697f0f0d840baf34ffe47f0db5fd9a4dbea4efe788bf5be7ae5a1fef3fefeefe7cb46afc77bd0f77c897f6dba37d1489b7b1c7ce6f21f5a27c68fc371dfb5bde1f1f408cf2b0e9f6b585ed6950958d278c0b2d85e15d6c2e05ebe27ddf6196e4593e940bca65b685040089410ae36edc136a62d1bf6c96e4593e940bca65b685040089410ae34cdc138a62d1bf0f1399fe40f46095975f68a18db2be37c4eb8fbc50b6fbad048d83f952848fd24a8f76868691fb3d5b9955846c0e38e77f08ad6bc138cf6b3ab01b94b87bf3ef819c58dbe1cf5359b9bdc2baa8ce4cbb76ededfb383607de0cf6536434a218207caf0ae0508cb2592395b69b7c6d0da69d69f20891b652491b32906b9283db24b61ea4af5152a7f57a83db261b0f527fbfe5", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "88f16c96df697e94640a6a2254100225002b8c86e004a62d1bffce7b8b84842d695b05443c86aa6f5a839bd9ab5893aed8e8313e94a47e561cc581c640d084eb6cff6496df697e94138a6a22541019128015c641704053168dff6196dc34fd280654d27eea0801128166e01ab82754c5a37f0f0d846da105dff3", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "885f87352398ac5754df0f0d830bc277f46196df3dbf4a09d53716b5040089410ae04571b794c5a37f7685dc5b3b96cff4f36c96d07abe940894d03b1410022504cdc6ddb81654c5a37f5585642e32f3e17f0badf1c220232b5c72f9cd774ac1a917e19a68b370a65e31d631e2f47779968e0ff8c0fe5a7162c59b63e2c1b2083ff2f1", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88c30f0d8308596b408721eaa8a4498f5788ea52d6b0e83772ff6196df697e9403ea6a225410022502f5c03f702ea98b46ffc35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46fc45585105a0ba1177f04aedc7d99f7519fc67aa2e9260d5e8df98bc4c6ab9facd5cf5f8e1b9c5a48f633e2bd7daee5c9b66729d5666efb2083f8f7", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88d90f0d03363336c36196dc34fd282029a889504008940b971b66e01b53168dffc8c2c16c96e4593e940094cb6d4a0801028215c0bd71a794c5a37f5585085f6de79a7f02ae4f8c72f4fcdfc9b9f0d17e17f31fb66e37797e7aea8c736ed3335c67f4cd284e0dfdfd6bc76337abfdece45b20837caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "88df0f0d03323436c96196df3dbf4a09c532db42820044a041704f5c644a62d1bfcec8c76c96e4593e940094cb6d4a0801028215c0bf7190298b46ff558679c69f65b77f7f04acc56c3e725590c3d856b0ed337e2ef0fcef44d7bb466fca3b5d1e1461e915442567efcb046141759f5c9b2083c3c2", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "886196dc34fd280654d27eea0801128166e01ab827d4c5a37fd20f28ba4753550547475355f6a5634cf031f6a487a466aa05c748fd9ea5c87a7ed42f9acd615106e1a7e94032b693f7584008940b3700d5c138a62d1bfff77f37910378716d73066dda6febfdbd81bdfb72ecf6f56401307f26b4dfd071b3af2f5efcb168f5b84da3a25dbd5e51128272dfe5d170e8debb24db8ecbd93ada2af1f4776d5bfc5027d9fddf2f3d1f9ff4db5f92497ca589d34d1f6a1271d882a60e1bf0acf70f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dfff3f2f10f0d83085a07f0", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88d66c96df697e94034a6e2d6a080112810dc6deb82654c5a37fefdedd5893aed8e8313e94a47e561cc581c136db22780fff6496d07abe94640a436cca080c89408ae043702f298b46ffc50f0d03363536d5", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88d96c96d07abe940054d444a820044a04171966e002a62d1bfff2e1e05893aed8e8313e94a47e561cc581c13cdb400bafff6496d07abe94034a6a22541019128076e32d5c03ca62d1bfc80f0d83109b0fd8", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88dc6c96c361be941054dc5ad410022500fdc6dbb810298b46fff5e4e35893aed8e8313e94a47e561cc581c13a2704f3ccff6496dd6d5f4a05f53716b5040644a04571a6ee36253168dfcb0f0d83081f7bdb", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "88df6c96e4593e94642a6a2254100225021b8d3d71b7d4c5a37ff8e7e65893aed8e8313e94a47e561cc581c640d81c034e7f6496e4593e9413aa6a2254101912800dc65eb8cb6a62d1bfce0f0d830b2d0bde", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "88e20f0d8308401f6c96d07abe9403ea65b68504008940b971a05c0baa62d1bfe55892aed8e8313e94a47e561cc581c105c6c2c89e6497c361be940b8a65b685040644a059b8dbf71b754c5a37ffd1e1", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "885f88352398ac74acb37f0f0d8313426be26196df3dbf4a05e535112a080112817ae36e5c0baa62d1bfe7e1e06c96c361be9403aa6a225410021500cdc659b8dbca62d1bf55850b2e044fb37f17add1b6bddb9cbbaf49ba7ae23abb4db5ca7d499bce2ae7c9666a1fe9be926298df82bf49394dc64c3e37ec178820dcdb", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "88c20f0d8365e00be66196c361be940bea6a225410022500f5c65ab82754c5a37febe5e46c96df697e94642a651d4a0801128266e361b800a98b46ff55850b211080cf7f02ac3ce81adc63c1a22a7711ec15570e0fcc09e0e69eadbefcd8bcf516148f895fd99bbd07ed1f8dd7a3f3a61820e0df", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "885f8b497ca58e83ee3412c3569f0f0d0132db4087aaa21ca4498f57842507417ff0", + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "2" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "nncoection": "close" + }, + { + "server": "Server" + } + ] + }, + { + "seqno": 47, + "wire": "886196dc34fd280654d27eea0801128166e01ab8c814c5a37ff17f1d9206dd1972fe62de1cdc7068fcfc678eecbaff4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f97f1db5d3db169c11b1ba5ebe73e4963d5ddd6676f2ddba4cfc74e2e98b3e67f15ed397c4cdefe42b323d7fcdbf891a3dd99dbe1fb3efe7fb7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab5f87352398ac4c697f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "88c57685dc5b3b96cf0f28ba4753550547475355f6a5634cf031f6a487a466aa05c748fd9ea5c87a7ed42f9acd615106e1a7e94032b693f7584008940b3700d5c138a62d1bff4085aec1cd48ff86a8eb10649cbf7f079108b47eede6cef85ffc7af5fe78eef16f7fc65886a8eb10649cbfe67f07b4a6845193463aff47e34e1462c20f21cfc7076b36f1c4c93aeae9fef5b3b76efcf4f8777cee1f3e475bc3d36e636823f454c0a8cdc6c55f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc4408cf2b0e9f752d617b5a5424d279a96591b132d32b09b8dc582128961902eacdbae3600b323aebedf5892a47e561cc5804f819034007d295db1d0627f0f0d83085a074084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "88d90f0d8413cfbcf7408721eaa8a4498f5788ea52d6b0e83772ff6196dc34fd282029a8895040089403d702cdc136a62d1bffc85891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96d07abe94132a65b6850400894102e32ddc6dd53168df55850884e81c6f7f18aba74e44ad505ccf7b2c867a92604d877ff389614e2d3bc45b51ab66747e7510ee9e18b3e2a9f35b8a3d90417caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "88e20f0d846402643fc66196df3dbf4a002a693f75040089403971915c65953168dfd0c5c46c96df3dbf4a002a693f750400894002e00171b7d4c5a37f55850bee32177f7f04aec392fc6fe1bdb356f1d6cd6d6571cdf4599247bc64fd8b2038787afcd9d9cd8bd6bc1a5bc3926edfad5dd75c3041c3c2408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "88d60f0d84136e3ef7cb6196c361be9413ca6e2d6a0801128105c65fb8c894c5a37fd56c96e4593e940bea6e2d6a0801128176e045704f298b46ffcbca558564217c0fbd7f03ac9f366a0de7618c0ef446f8e2be6bf7eb9f9b39f0703e4ee26bb3fc65bccf0d49aeacbc5976dcfcb8574f8820c8c7", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "88eb0f0d84138c843fcf6196e4593e94642a6a225410022502e5c6dcb8d094c5a37fd9cecd6c96d07abe940b6a6a2254100225040b8166e32053168dff5585134d89c7bf7f02aba2be010e4d81e913a7a5e8b0f1c99d1eff437b07159ef70cc17459455cef5088fb2599ec972d5b9d2ec820cccb", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "88ef0f0d8465a6de73d36196df3dbf4a09b535112a080112820dc65ab807d4c5a37fddd2d16c96d07abe941094d444a820044a05cb8cb3702d298b46ff558575a74020ff7f02adbfa631a7d20b57e0b3f0e0e79eb6ea668c44f33dfe3f82bf89bbdefb71e15e7c7afc2d9d62eeda9a9d8bbf8820d0cf", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "88e87f1b9a005a232cba0584dc6eac10944b46d38359d64a21bcc85f70b27fe3e5e40f0d023533", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "88e9e1e8e7e6e5e45f89352398ac7958c43d5f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffe36c96df697e941054dc5ad410020502edc65db8d054c5a37f0f138cfe5a69e716748d8dc65a07f352848fd24a8f0f0d83136f83", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "885f87352398ac5754df0f0d8465b6da0fdc6196df697e94640a6a225410022500edc002e002a62d1bffe66c96c361be94134a436cca080112816ee05fb821298b46ffdcdb558565c75a71ff7f07abeb5eebaf43d1a40b6121dce39b851bb4dd5bc517a5f14c9979509bc09408d6441b9f72608cc9bb59f64107d9d8", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88c20f0d84642cb4cfe06196c361be94138a6a2254100225041b8176e34053168dffeadfde6c96e4593e94134a6a225410022502f5c13571a6d4c5a37f558571c0b8107f7f02ad3337b7fa9dc4539376be3b1dcfdb2f06f5ec6f670f18e4d76fe9b723c4d9a7a826db668daeb3e5be7b26a26820dddc", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88c60f0d84640f85ffe46196c361be940bea6a225410022502e5c643704ea98b46ffeee3e26c96df3dbf4a099521b665040089410ae043700153168dff5585089e65b7997f02aea5ea52f3866e7d583c861d15ed8cee76bbef0f9ed97b6fce5eaf7bf5cb0f3e9e7a0b4e1dee562f5b63abf7c4107fe1e0db", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88f16c96d07abe941094d444a820044a05bb8205c69953168dff5f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6ff75892aed8e8313e94a47e561cc581c64020b2d3606496dc34fd282654d444a820322502e5c10ae000a62d1bff6196dc34fd280654d27eea0801128166e01ab8c814c5a37f0f0d8365f75eee", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "88f76c96dc34fd28012996da9410022502edc13571b0a98b46ff5f86497ca582211fc35a839bd9ab5893aed8e8313e94a47e561cc581c0bafbacb6077f6496c361be94034a65b6a5040644a0017042b8dbaa62d1bfc30f0d83132d8bf3", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "887685dc5b3b96cf6c96c361be9413ca6e2d6a0801128076e01bb8cb2a62d1bfc3c8c25892aed8e8313e94a47e561cc581c13c203421356496df3dbf4a32053716b5040644a041702d5c6da53168dfc70f0d83105f17f7", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88c16c96d07abe9413ea6a2254100225000b8c86e05f53168dffc6cbc55893aed8e8313e94a47e561cc581c640d36db826bf6496df697e94138a6a2254101912810dc65eb81694c5a37fca0f0d830baf33408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88c50f0d8365d6856c96e4593e940b2a65b6a504008940bf7197ee36fa98b46fca5893aed8e8313e94a47e561cc581c0bccbcf36fb9f6496df697e9403ca65b6a5040644a05fb8d06e01c53168dfcec1d1cb", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88e00f0d03333539c16196d07abe94132a651d4a080112817ae34edc6de53168dfc95891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96c361be94089486d99410021502cdc699b8d32a62d1bf558410197c1f7f1aaecc19ef72a7cbbb4b77ca3f1b6ff2d87af4c7f98014ed465e991b05ba73606f170bbd9add2616b7fbf3a565a1820f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "48826402d7d158b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007f4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff4003703370c1acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7e94bdae0fe75ee84ea6bdd7cea6ae1b54dd0e85356fdaa5fddad4bdab6ff30f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813f4087aaa21ca4498f57842507417f0f28d11c8b1a4821775f3a7d0a5ba0edfb561f13d2644983ce8ff89fb52f9e919aa8171d23f67a961c88f4849695c87a7ed4c1e6b3585441be7b7e940056ca3a961019754002e001700153168dff6a6b1a67818f7b9384842d695b05443c86aa6fae082d8b43316a4fda0f0d0232305f87497ca58ae819aa", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88ded8c4c3c2c10f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813fc00f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c7bfdb0f0d82105d5f95497ca589d34d1f649c7620a98326ed4b3cf36fac1f408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88e0dac6c5c4c30f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813fc20f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c7c1dd0f0d03313538bfbe", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88e0dabfc2c1dd0f0d820b80", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "885886a8eb2127b0bf0f0d0234325f87352398ac4c697f5d9a9d29aee30c22b2ae34c94a5721e960d48e62a18acde4b42f31a56401307f08c9bdae0fe74eac8a5fddad4bdab6a97b86d521bfa14bf838a9be1c87535ee84ea6bdd7cea6ae1b54bbc3729c34e4535f0daa5ed5a14d30f153269dea5fc1a14ddbe1535edc0a6adf7bf90f28d0d1c325f8197af5f79e089c7b0dd704f6066fb217af070b9770dd704f3ff6a17cd66b0a88341ea907ebe94032b693f758400b4a0017000b800298b46ffb52b1a67818fb5243d2335502e34c94a5721e9fe57f19842507417f", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "887689bf7b3e65a193777b3feb0f0d03333133e46196dc34fd280654d27eea0801128166e01ab8c854c5a37f", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "88c50f0d023432c4c3c2c10f28d0d1c325f8197ef05e699bb7ddbd75c75fc00704cbc065cbed5ebae3a0bbf6a17cd66b0a88341ea907ebe94032b693f758400b4a0017000b800298b46ffb52b1a67818fb5243d2335502e34c94a5721e9fe8c0", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "885f8b497ca58e83ee3412c3569f0f0d8371f6c3e9e3", + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "6951" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + } + ] + }, + { + "seqno": 73, + "wire": "8bc50f0d840baf34ffdc4088f2b0e9f6b1a4585fb5fd9a4dbea4efe788bf5be7ae5a1fef3fefeefe7cb46afc77bd0f77c897f6dba37d1489b7b1c7ce6f21f5a27c68fc371dfb5bde1f1f408cf2b0e9f6b585ed6950958d278c0b2d85e15d6c2e05ebe27ddfc16c96e4593e940bca65b685040089410ae34cdc138a62d1bf0f1399fe40f46095975f68a18db2be37c4eb8fbc50b6fbad048d83f952848fd24a8f76868691fb3d5b9955846c0e38ff7f1aade1762a2eb66e8971d7b60bc6566ee55b8444e3dd3baae50f19786ffc25ecd3ceb6c867c9b1fbb7a3664e9b20837caf0ae0508cb2592395b69b7c6d0da69d69f20891b652491b32906b9283db24b61ea4af5152a7f57a83db261b0f527fbfd9", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88c7408cf2b0e9f752d617b5a5424d27990046f3cc900b09b8dd582128961902558afbb23c169d7c8f37ced3ef0f0d023533", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "88c8ec0f28ba4753550547475355f6a5634cf031f6a487a466aa05c748fd9ea5c87a7ed42f9acd615106e1a7e94032b693f7584008940b3700d5c138a62d1bffd74088f2b0e9f6b1a4583f90037af90316f007672d6d35830e6c20c17f0dff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f95886a8eb10649cbfcf7f0ab2c57a73b14e5d57db0eab65374ede1c9bb5738580a321a1bd8af66cbf99a717baf40eff472d6e684334dcad4111c9919fa64fd7f3d20f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f7f049a96591b132d32b09b8dc582128961902eacdbae3600b323aebedf5892a47e561cc5804f819034007d295db1d0627f0f0d83085a074084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "885f87497ca589d34d1f0f0d03313837ee7f04b41ffb468772d5983edefccb0e7c6eb0c38c6bb3f327aedb936bdabf2bc3e789c7f8e4c3e5c25fdc37da770d82d9b380d896b761c97f108c0b2f3cfbede0bd79b03216c36196d07abe941094d444a820044a05db8272e36ca98b46ff409ff2b0e9f6b52548d6e854a194ac7b0d31aa1d0b4a6a0ab4834956320ef3800f92100215821580eef106e32cdc69a5c0007eff408ef2b0e9f6b52548d6a646d69c689f961881246d3201800103f23c00bcd36e80a4146dc8cbc5588aa47e561cc581e71a00016c96df697e9403ca693f7504008540bd71976e042a62d1bf0f1399fe4620491b4c80600040fc8f002f34dba029051b7232f17f9fd3d255850b6e81b7ff7f12acce873233ee7cfb7c2de8199e1e4e15f532df8334b9bd70bb928edd336d4c23d99021e7e02cb7d217a19e68207caf0ae0500e46cbd18a49091c6d36478acb3246170231321702d3eb9283db24b61ea4af5152a7f57a83db261b0f527fbfed", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "88c80f0d8213227f1e88ea52d6b0e83772ff7f09b4e8e0b847e3acf3762b0e63e1479f4e43361c38591be93dfff7bf5b7ab13499ecf5c3d7786dc9b7ae0d7fbeeade4c1d514105dedf7f098dbe2684fb97ef32d33819bed5ffc87f089210022580f2cc83785eb800dc69c5c0007eff7f0897191f1332c6e371b2e46e95c9250c6f36591f188a58c4dfc76c96df3dbf4a320521b66504008940bd7002b82654c5a37f0f139afe4647c4ccb1b8dc6cb91ba57249431bcd9647c622963137fcffdcdbc67f06adb5ac7e6429b5f417eb8fd1b1d1f5f4f6bf1b598f2670dfc82cffbdcd7acc0692f17369dbf993deee006b1f8820c5f4", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "88cf0f0d03323436c47f04b485eaf5170eff5ef952eb93fe70730cb9faec95a23fe3f6f6a943b30bfb5adf8baf4fcc192ad996b7251d9d7acc0e57418e5f04cd7f048c6ae819142fb8cbb7dd0bd7dbce7f0492100215821580f6f0bd7197ae32eae0003f7f7f04971c71802f3318c6028df7db8da764210057df74407db1ffcd6c96df697e9403ca693f7504008540bd71a0dc0094c5a37f0f1399fe471c600bccc63180a37df6e369d9084015f7dd101f6c7fcfe2e1cc7f04ac38051e5e5c22e9bb038e64f19f761433daaae4873ecdb313036ced2d90830e919e7ab2563f586dc97794d041cb4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88d60f0d82109dcb7f05b67f3e5f6edffcd5978f60f7ff6e74d9775f2ff7af343a7d7fb7b85db3aa76f0af73744923b538d4ba1bba093befc1c7ab27cdaa11ece97f058d77004583032f5fbcddfc0ce1076196c361be94138a6a2254100225040b8db771b0a98b46ff7f069110022580d2c10ef0bd71b7ee002b8000fd7f06972b4dc6f142075a96371b2b4d3b23923c37c25965786fb5d56c96e4593e94085486bb1410022502f5c6dfb8d32a62d1bf0f139afe4ad371bc5081d6a58dc6cad34ec8e48f0df096595e1bed7f3feae9558571c13e20ff7f07aebae6977bb5fb9fdd987d71dbc7ce924fbfd71d42b6ad5ef2e3c99997fb3dbb2990e91caf959935786acbc1d9041fd4c6", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "88de0f0d03323336d37f06b5677f125b6b9a363ce969ff78a4c9fedff627688eff9fce0d99fc6ffefb7f1648e9659bbfa77fbeb9b25e621ea6a2ee66d385d6f67f7f068dc21036e3cfbaf86f3d7b0de73fc57f059210022580dac17b785eb8d39700d2e0003f7f7f05978c2175e91a96368210c81036f0c2f3a4959091f6c71bffdc6c96c361be940bca681fa504008940bd71a76e042a62d1bf0f1399fe63085d7a46a58da08432040dbc30bce92564247db1c6fff352848fd24a8f76868691fb3d5b99c67f06ad466d73f3e1e87e36d9979552f247ac59c48649d6ed471d79767397cf7ac3c99cdc7378d06e13f5c199b0f8820fdcce", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "488264025f92497ca589d34d1f6a1271d882a60b532acf7f7f3099bdae0fe6f70daa437f429ab86d534eadaa6edf0a9a725ffe7f7f1f842507417f0f1fbe9d29aee30c2171d23f67a961c88f4849695c87a58292967fc2f980f596af2b90f4fc1a481a00dc08652ac07257d6246eb4b09c1bcb3b1b659081101b2bbf0f0d01300f28c534048e42362906b46cc8d2cd4aebeb464740b3211064001c964947f6a772d8831ea803f6a5634cf031f6a487a466aa05cf596af2bd454fda948fcac398b038c81d10000fbf", + "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;" + } + ] + }, + { + "seqno": 82, + "wire": "c16196dc34fd280654d27eea0801128166e01ab8c854c5a37f7690dfb75a90d6324e55af1fd1d25602b87f7f02afbdae0fe74eac8a5ee1b46a437f40d4bf8388d4df0e41a9ab86d52ef0dca64d37d4e1a72297b568534c3c54c9a77ff30f1fb79d29aee30c2171d23f67a961c88f4849695c87a58292967fc34907c17cc165b19887aabb0fd0a44ae43d3f0848d36a20a8eb5a82d8b1a40f0d01305885aec3771a4b0f28abdd836f1c1b725f83ed4c1e6b3585441be7b7e940056ca3a960bee814002e001700153168dff6a5634cf0314088ea52d6b0e83772ff8d49a929ed4c0dfd2948fcc020037f0488cc52d6b4341bb97f5f93497ca58ae819aafb50938ec4153070df8567bf", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "885f87352398ac5754df0f0d84081f75ffe76196dd6d5f4a082a6a2254100225002b8d3571a6d4c5a37f7685dc5b3b96cf5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df697e94038a681d8a0801128215c102e09b53168dff5585085c032f397f11adc21bb550d65dcfe6f5ed6d4d92bb7f0b3022e8de2b69bf30b6243e2b07b3d5efbf9d78b25ee94f0dc5d134107f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbfe2", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88c60f0d830b6273ef6196dd6d5f4a082a6a225410022500fdc002e044a62d1bffc56c96c361be940b6a65b68504008540bf71a15c65c53168dfc5c45585085975e6df7f03aecb8b3ed9aeb9469e83f37e49a6d31bf97aea6de8bbe7eb8e9e1b4bfaf358ba7acf3841871dee97ff43205bd9041fc2e6", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88d1c858b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007f4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff7f13c1acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7e94bdae0fe75ee84ea6bdd7cea6ae1b54dd0e85356fdaa5fddad4bdab6ff30f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813f4087aaa21ca4498f57842507417f0f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c77b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab0f0d0235375f87352398ac4c697f408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88dad1bfc2c1c00f0d023537c6c5c4", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "88d16c96c361be94101486bb14100225020b806ee34053168dff5f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6fc35892aed8e8313e94a47e561cc581c0b4e81d70426496df697e9413aa435d8a080c8940377021b8c894c5a37f6196dc34fd280654d27eea0801128166e01ab8c814c5a37f0f0d83081f6f7f1c88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88da0f0d840842177fbe6196d07abe9413ea6a225410022502e5c6dcb8d814c5a37fd9d8d76c96d07abe94134a6e2d6a0801128205c69ab817d4c5a37f5585682f01c0ff7f12ad6cf15d3701ef86fb7473d88ccd64e2deff7db6364e5cf4ec8ea483ce7f1ecadf4dcb34d378306d2277e19a083fd64085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "885f88352398ac74acb37f0f0d84642d381fc46196e4593e940baa6a225410022502f5c13f704d298b46ffdf6c96df697e9403ea6a2254100225042b8d06e05b53168dffdfde55850b4d3ec81d7f04ad4f87d66b978d3775f324910aa6fc005bb777c39fdf3ddb2c775cc7e5570ba72f5efd22bd0f7cfc13ecc49a083fdcc3", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88e26c96df697e940054dc5ad41000fa820dc0b9704e298b46ffcecdd25893aed8e8313e94a47e561cc581c0bcdb606db7bf6496df3dbf4a040a65b6a5040644a05cb8d02e09f53168dfee0f0d8364416fcb", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "88e56c96df3dbf4a080a6a225410021500f5c64171b7d4c5a37fd1d0d55892aed8e8313e94a47e561cc581c0b2c884f3206496dd6d5f4a042a435d8a080c8940357190dc682a62d1bff10f0d8365b685ce", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "88ea0f0d83101a6fce6196d07abe940b8a65b6850400894037704e5c65d53168dfe9e8e76c96e4593e940b2a65b6850400854106e360b8db4a62d1bf55867db642d3ad7f7f08adefd27a5ff69050d0fabf66f9483ec7bf8f1f6bdc7d74f4ddddeb0307e79cde81b2d0df7715bb3396df19b64107e6cd", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "f90f1fcf9d29aee30c2171d23f67a961c88f4849695c87a58292967fc2f98243db1d0525062755ea2a7e2639e6a0b14c6920bd0e0dd82fd6e7bdf8aac1c7561fcde8e1bf2549a351fe2639e6a0b113b96c803ff5e06496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a1271d882a60e1bf0acf7768abc73f53154d0349272d90f0d826420408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88f16c96c361be9413ea681fa504003ea08171b72e09d53168dfdddce15893aed8e8313e94a47e561cc581c0b2cb6e85c6bf6496dd6d5f4a042a435d8a080c8940b5700cdc6db53168df6196dc34fd280654d27eea0801128166e01ab8c854c5a37f0f0d03373339db", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "88bef5eae9e8e70f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813fe60f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c7e5e40f0d023537e3e2", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88d50f0d84132f381fdb6196df697e9403ea6a225410022504cdc69fb8dbca62d1bff6f5f46c96df697e9403ea6a225410022504cdc133700ca98b46ff55851044113acf7f0bad70d35ef686fddfdb5cb4336edc181ee0f46ef04702e636afca2adadeaf12dfc2d6edb7fc68f76b550b1f9f1041f3da", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "886496dd6d5f4a01a5349fba820044a01cb8272e05a53168df6c96e4593e94036a6e2d6a080112820dc0bb702fa98b46ff0f1392fe42fb207c61585185b58ae371c8d901fcff588aa47e561cc5802e89e003769186b19272b025c4bb2a7f5b4b2298c69fef52848fd24a8fed7f31ff46bdae0fe74eac8a5fddad4bdab6a99e1e4a5ee1b5486fe83a97f0713a9be1c87535ee84ea6bdd7cea64e309d4c9c6f9d4c79371d4d5bf59d4d5c36a9ba1d0752ef0dca70d3914bdab429a61e2a64d3bd4bf834297b4ef5376f854d7b70299f55efe7e94bdae0fe74eac8a5fddad4bdab6a99e1e4a5ee1b5486fe83a97f0713a9be1c87535ee84ea6bdd7cea64e309d4c9c6f9d4c79371d4d5bf59d4d5c36a9ba1d0752ef0dca70d3914bdab429a61e2a64d3bd4bf834297b4ef5376f854d7b70299f55efe7f0f0d8365e7c3cec8e5e9", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "48826402768586b19272ff7f01c7acf4189eac2cb07f33a535dc61848e65c72525a245c87a58f0c918ad9ad7f34d1fcfd297b5c1fcebdd09d4d7baf9d4d5c36a9ba1d0a6adfb54bbc37297f76b521cf9d4bdab6ff30f1fbe9d29aee30c2171d23f67a961c88f4849695c87a58292967fc3490472c827c3201613e369668ac8161b2312cf82394842b6191e97e0be601c9496891721e90f0d033237355f95497ca589d34d1f6a1271d882a60320eb3cf36fac1fcce90f28d3a4b449120a84411cb209f0c80584f8da59a2b20586c8c4b3e08e5210ad8647a5fb2f9acd615106eb6afa500da9a07e941002ca8066e36fdc642a62d1bfeeb1a67818fb90f48cd54091ccb8e4a4b448b90f4fdf", + "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;" + } + ] + }, + { + "seqno": 99, + "wire": "886196dc34fd280654d27eea0801128166e01ab8c894c5a37f7685dc5b3b96cf58b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007f4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff7f05c1acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7e94bdae0fe75ee84ea6bdd7cea6ae1b54dd0e85356fdaa5fddad4bdab6ff30f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813f4087aaa21ca4498f57842507417f0f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c77b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab0f0d0235375f87352398ac4c697f408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88c70f0d837de65a6c96df697e940b4a436cca080112807ae05fb8c814c5a37f5f911d75d0620d263d4c795ba0fb8d04b0d5a75892aed8e8313e94a47e561cc581c132e880265b6496d07abe9403ea436cca080c89408ae341b8d38a62d1bfdb408721eaa8a4498f5788ea52d6b0e83772ff7b8b84842d695b05443c86aa6fc6", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88cd6c96e4593e94136a612c6a08007d40b771a7ee34f298b46f5f86497ca582211fc0c8588da47e561cc581b780db4e3afbdff0e00f0d03333439c2408af2b10649cab5073f5b6b9bd19376e525b0f4a8492a58d48e62a171d23f67a9721e9b81001e07", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "885f88352398ac74acb37f0f0d841381087fc46196df3dbf4a002a693f750400894102e36edc0054c5a37fd35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a002a693f750400894102e36edc0054c5a37f55850b4d34d87f7f24ad0b5f8ee18f678c991de4c8b3628aeb9c2ad9ee187481accd13de4ef5ecfca24b32f5f415b945873640784430417caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "886496d07abe9413ea6a2254100225040b8066e084a62d1bff6c96df697e940814cb6d0a080112807ee36ddc13aa62d1bf0f1391fe42fb20189b584223ab46392328480fe75891a47e561cc581f034000000fa52bb63a0c4e5e4d6e30f0d8313a07bd2decfce", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "88dd6c96e4593e940bca435d8a0801128105c69db81794c5a37fd3cfd75893aed8e8313e94a47e561cc581c132eb2fb4f3ff6496d07abe9403ea436cca080c8940bd7002b8d054c5a37fe10f0d83138217d2cd", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "886196dc34fd280654d27eea0801128166e01ab8cb2a62d1bfe56c96c361be940094d27eea0801128205c033702da98b46ff6496df697e94038a693f750400894102e019b816d4c5a37f0f139fc17e186fc20bb76f8b036d05e730dd75ebf82f5fbaf030070000fb408597e158a4a47e561cc5804f32e883f55db1d0627d54759360ea44a7b29faa6d4256b0bdc741a41a4b408df2b1c88ad6b0b59ea90b62c693884bc59083391158bf0f0d033437317f18842507417f5f911d75d0620d263d4c1c88ad6b0a8acf520b", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "88c4eb6c96dc34fd280654d27eea0801128172e32ddc65953168df6496e4593e9403aa693f7504008940b97196ee32ca98b46f0f13a00bafde8458306115d770e07dcbb79f7ef362bed3b7430b981fc0cb9870b30bbf58a5a47e561cc58196dd71b7feabb63a0c4faa8eb26c1d4894f653f54da84ad617b8e83483497fc30f0d03343731c2c1", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "88eb76b686b19272b025c4bb4a7f5c2a379fed4bf0f1604a5279224228604b897694d5596addbb3b005df5dd1a949e48a51a12498cc09769717f0f28dacd0dfe1bb06dbdab566c982085c78576f32fad81f65959a8705f59e72fb2b38fc30e01430df08b0fda921e919aa82bb63a469311721e9fb50be6b3585441badabe94032b693f758400b2a059b806ae32253168dff6a5634cf031dce47f28e2bdae0fe74eac8a5fddad4bdab6a99e1e4a5ee1b5486fe83a97f0713a9be1c87535ee84ea6bdd7cea64e309d4c9c6f9d4c79371d4d5bf59d4d5c36a9ba1d0752ef0dca70d3914bdab429a61e2a64d3bd4bf834297b4ef5376f854d7b70299f55efe7fc4798624f6d5d4b27f5f87497ca589d34d1f", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88cbeeedecebea0f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813fe90f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c7e8e70f0d023537e6e5", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88cb76bd86b19272b025c4bb4a7f5c2a379fed4bf0f1604a5279224228604b897694d5596addbb3b005df5de2ad29ab42d64e5a1b5293c914a34249319812ed2e2e0e8c1c7c0bf", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88ef6c96c361be941094d444a820040a05fb8c86e36053168dffdfe1e9588da47e561cc581b7996df6df71efcf6196dc34fd280654d27eea0801128166e01ab8cb4a62d1bf0f0d03333535e4df", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "88f26c96df697e940b8a6a2254100225041b8072e05b53168dffe8e4ec5893aed8e8313e94a47e561cc581c640d3cd85e77f6496df697e94138a6a2254101912817ee361b800a98b46ffc10f0d836597dee7e2", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "88e10f0d84134cb4dfe76196e4593e940814d444a820044a00171976e05f53168dfff6e0df6c96df697e9403ea6a225410022504cdc133700d298b46ff55851042f34cb77f1faf4e7d4df5b39477b9d3b697f3e4e9f97f4bae4b7857f2cfbf71b46767979775b78b7c5b25a396cf7d3a7acfbbc4107fdedd", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "887685dc5b3b96cf6c96d07abe9403ea435d8a080112806ae01eb8dbca62d1bff0ecf45893aed8e8313e94a47e561cc581c0b2cba20bacff6496dd6d5f4a042a435d8a080c8940bd702d5c03aa62d1bfc90f0d8365f745efea", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88e90f0d84105d659fef6196dd6d5f4a082a6a2254100225001b8cb37196d4c5a37fc2e8e76c96d07abe9403ca6a2254100225040b8066e040a62d1bff5585085c69c7017f06ad8cfe817fa73c86eefec35fe10dd6f26f0327cbe01a8ab6ff7b3b0bd8f3c71de796d17b74543996cf72b734107fe6e5", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "88c56c96c361be940094d27eea080112806ee36ddc69b53168df5f911d75d0620d263d4c795ba0fb8d04b0d5a7f45a839bd9ab5893aed8e8313e94a47e561cc581c640e01e132eff6496df3dbf4a09e535112a080c8940397001b8d894c5a37f6196dc34fd280654d27eea0801128166e01ab8cb6a62d1bf0f0d840bae360f7f2088ea52d6b0e83772fff5", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "88f40f0d84132fbee7be6196e4593e94134a6a2254100225000b8cbf71b654c5a37fcdf3f26c96d07abe9403ca6a225410022502e5c0bd71a7d4c5a37f55857c0f38f0bf7f09aeed7a2dbc73839e7f3ccf77b8ff416f68d02e391ce9826e1d596b6f50bfdabc526e171461e1b99cdd7973d134107ff1f0", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "885f88352398ac74acb37f0f0d84105b785fc36196c361be940bea6a225410022502f5c69db8dbca62d1bfd26c96d07abe9403ca6a2254100225040b8066e042a62d1bff5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f5585089d6d97dd7f05aeef8fb66dc9dbf9975f341b37bdc04eff1ce20fe663754398fbf8cb8b7bfc21b37512c28735557b9e3d8ed10c107f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88c60f0d841082cbffcb6196df3dbf4a05e535112a080112807ee01bb81714c5a37fdac4c36c96d07abe9403ca6a2254100225040b8066e044a62d1bff55860b2fb8eb6fff7f04ac64ddb759e806678cfdbd5b7781d636de4cf09b06edda6eec668eed732e14f9d66896849dda73a25cc90f8820c3c2", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "885f87352398ac5754df0f0d03383439d06196df3dbf4a09d53716b5040089403b704f5c0bca62d1bfdfc9c86c96dc34fd281714cb6d0a08010a8005c641704253168dff5585644171f75d7f03aee93b2e6ed1bbf07f9d22de5dbb5ff6d7143cb1238f01f1edc597afb5bdf2f1daadf7fad4cd3c1de5cf264cfe2083c8c7", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "88e26c96df697e940baa651d4a080112800dc0bd719794c5a37fda7b8b84842d695b05443c86aa6fda5893aed8e8313e94a47e561cc581c0b2cb6e884d7f6496dd6d5f4a042a435d8a080c8940b5700d5c6df53168dfd90f0d8313206fd8408af2b10649cab5073f5b6b9bd19376e525b0f4a8492a58d48e62a171d23f67a9721e9b81001e07", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "885f87352398ac4c697f0f0d83138d37da6196df697e940b8a6a225410022502d5c6c1704f298b46ffe9d3d26c96c361be941094d444a820040a099b8db3704ea98b46ff55860b6d3cf34f7f7f08acdbcfc27cb6303e54d83fdc746a7b8256de41fb46c9c7934518d17a2cbbfddec1f90f32fe4b4c73821e50c107d2d1", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "88ec6c96df697e941094d03f4a0801128105c037702253168dffe4c7e35893aed8e8313e94a47e561cc581c132eb2fb4f3ff6496d07abe9403ea436cca080c8940bd7002b8d34a62d1bfe20f0d03363536e1", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "88c50f0d03353930e16196df3dbf4a05f532db42820044a01db8072e05f53168dff0dad96c96e4593e94038a6a2254100205040b8d3b702f298b46ff55857c4e3827dd7f05ade9a3ac5cb3c2ea76e21fbeff8c98a5abf5eb75e7ebaae874f1e95514dbb716bdbae5e18ab9253d797968b66820d9d8", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "88d30f0d03363138e56196c361be940bea6a225410022502edc0b971b7d4c5a37ff46c96c361be940b4a6e2d6a080112816ee05bb8c854c5a37fdfde5585089e03cdbb7f02ac9914ad6728ba47876945a4af8b5492481676e035daaffb3bfd5b675b6fe7e4b39cbf67e987318535649a083fdddc0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 125, + "wire": "88d70f0d8371a03fe96196dc34fd280714d444a820044a01bb820dc6de53168dfff8e2e16c96e4593e94136a435d8a080112806ee01db8cbea62d1bf5586134d38fb6f7f7f02adda5aaf84e3d17eebbcafc20ab2dd36f75ed777a55d3853cf82da77b2b177519ff00cf66fbe80b94ec4cf34107fe1e0", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "88d10f0d840b2f85bfed6196df697e94640a6a225410022500ddc6ddb8d054c5a37f7685dc5b3b96cfe7e66c96d07abe9413ea6a225410022502fdc106e05a53168dff558565d0882dff7f03adf4b76ebea2b77702c75fb3f3cd8b9e81868f788bc2df2d4b3554ed9fc759bbd9f9b2a75ea31370cf2e1a61820fe6e5408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "88c26c96df697e941094d03f4a0801128072e341b8cbaa62d1bf5f86497ca582211fddf95893aed8e8313e94a47e561cc581c10596d9742eff6496df697e940b2a65b685040644a019b817ee36ca98b46f6196dc34fd280654d27eea0801128166e01ab8cb8a62d1bf0f0d830b6f03f8", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "88f30f0d8369a6dcf86196e4593e94642a6a225410022500ddc13971b654c5a37fc8f1f06c96e4593e94642a6a225410022500ddc1397191298b46ff558513ce38e33f7f08add90f2c30e13ecedda4cce4682c76f000704b8b8def1bb8c58fa2778f3c2b4f46f861d50b9235c91edaf134107ff0ef", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "88f70f0d8313ed87408721eaa8a4498f5788ea52d6b0e83772ff6196c361be940094d27eea080112817ae32f5c682a62d1bfcd6c96e4593e94642a6a225410022500ddc139719694c5a37ff7f6558471c65b6f7f03ad86d8e36f45b77509ebe2c8f74c97f8f3e54e412cf4cd6f48095d0e465d04af8eed3bff1b9bf74776bc4db2083ff5f40f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 130, + "wire": "885f88352398ac74acb37f0f0d8369c71cc36196df3dbf4a002a693f7504008940bb71b7ae32d298b46fd25891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a002a693f7504008940bb71b7ae32d298b46f55850b6d85c17f7f05add57654b3eabaedddbfd646ced8bf770dba258fa7ef2ad9dd3fbc2f2d26869bd7283b75cb939ce26aad89d9041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "88c60f0d836c2f8bcb6196df3dbf4a002a693f7504008940b97197ee34fa98b46fdac5c46c96e4593e94136a65b6850400894086e045719794c5a37f558471f7c4cf7f04afe6e6e6bd556f693972bfa64c5a7bfe694f0725ab4ddbba8f973f2e3ae49e6abd60ab7efd17fbe489afcb747bd9041fc3c2", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88ca0f0d836db13fcf6196e4593e94642a6a225410022500cdc683702253168dffdec9c86c96e4593e94642a6a225410022500cdc0b7704e298b46ff558513ec800d7f7f02addd3e8f07fcf54bdf9a71b5b832e1fc0b7bee93a5d31f98e6bd94776bb2fc7d87a9397a6a369ebca42ccecd041fc7c6", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "88ce0f0d8365c13fd36196c361be940bea6a225410022504cdc0b771a7d4c5a37fe2cdcc6c96dc34fd282654cb6d4a080112820dc65db81654c5a37f5585089b7d913b7f02adc747ad1b9a69c40de79cb753b7fa65f5c07df90d6a71e307e6727af7c2c8da7f32d89aa7af6d11eed48c90c107cbca", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "88d20f0d8365b03fd76196c361be94136a681fa50400894133700cdc036a62d1bfe6d1d06c96df3dbf4a09a5340fd2820044a05eb8cb7702f298b46f55860b2fb8079f0f7f02ac5b27ead9bdc94347dfa1d75cf312dba4c8b6e956b24bb801e4b9b9f7a7a08e9d5a6eb535b6b34028d2886083cfce", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "88d60f0d8369e75fdb6196e4593e94642a6a225410022500d5c65fb81694c5a37fead5d46c96e4593e94642a6a225410022500cdc0b571b6d4c5a37f558513cfb6217f7f02aee1575f78337e48d5ff18bbe7e19d67961cbcbdf1c7a0975adeb279d8fad8f3f2c3b512c66c9df9faa3c64f30c107d3d2e9", + "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" + } + ] + }, + { + "seqno": 136, + "wire": "88da0f0d8313c07fdf6196c361be940094d27eea0801128176e09ab8d34a62d1bfeed9d80f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96df697e940854dc5ad4100225021b8d06e09b53168dff5584740ebe2f7f02ad86bd9b89ef6bbde66f65e93ce3fddae4f7690d71d0b4f8bbd7e757b7346badf2dec07bbe5f7f23cb0d3f934107d7d6", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "88de0f0d830beebfe36196e4593e94642a6a225410022502f5c0b3702f298b46fff26c96e4593e94642a6a225410022502f5c0b3702f298b46ffdedd5585134071d7bf7f02aee5dfbeee5bb1478aeedc765d941b70f4cacf6cb11daf4ffacb6ef7b71715fec192be7dfc6f874d9e3d58b6af1041dbda", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "88e20f0d8371f685e7e1f5dee0dfdd7eacfc862e8cd3c7c74465d1be6c6523383468df95b69df60fca726bc6f4f4684b69b740756028b35a78a17a6820dcdb0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 139, + "wire": "88e30f0d830bcdb5e8d6f6e1e06c96e4593e94642a6a225410022500cdc0b7704da98b46ffd57f00adb35e9e19620736adc00e59b3eac3fb249c52feb4ac16cde48f687f973c3e7f49e7876101ad7825d29e36f8820fdedd", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "88e50f0d8365c703ea6196df3dbf4a002a693f7504008940b97040b8d814c5a37f7685dc5b3b96cfe5e46c96df697e940854dc5ad4100225041b8d06e084a62d1bff55840b81009c7f03ae083973efbebcba7063068875b3e2a282bfcfcd381efdaa1c8d178e5859c17f5d995cdf859b3b839e5cb9a286083fe3e2", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "88ea0f0d8313a27fef6196df3dbf4a002a693f75040089413371a66e34ca98b46fc2e9e86c96e4593e940054cb6d4a08010a806ee09ab8cb6a62d1bf5584740eb6ff7f02adeb18aad1dbba44fece8ce7909e3739e3c0731e3d19fdf0a32f2e9ef07b972b4fcf664e7c5f8493ea1d556c820fe7e6", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "88ee0f0d8365f0b9f3d1c5eceb6c96c361be9403aa6e2d6a080112807ee019b8cbaa62d1bfd07f00aecb97f6fc7a36b5b73e9cd163e3df7c7c2ad23be6a2f09aaf25da53cddbbb646f2f5d9ea3c7367d7973d82bbe2083e9e8", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "88f00f0d831040cff56196e4593e94642a6a225410022502f5c0b5702da98b46ffc8efee6c96e4593e94642a6a225410022502f5c0b5702da98b46ff5584134070417f02ac8713f38227e1ddb6d9c79fa4f75a9511f7c0e754d651c791beefee5a5dd962cc1ddaa4b1e475f28d8f43041fedec", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "88f40f0d8310440f408721eaa8a4498f5788ea52d6b0e83772ff6196e4593e94642a6a225410022502f5c13f71b1298b46ffcdf4f36c96e4593e94642a6a225410022502f5c0b7700e298b46ff5585132fb8f35f7f03ad678bfef7092e874e6d58fa116f71ec3171f87af85bbb85e7b1e86eff1d9cdfe8dfb77b0fce07b2dfc71fa86083f2f1", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "885f88352398ac74acb37f0f0d83101c6fc36196c361be940094d27eea0801128176e09bb82794c5a37fd25891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df697e9403ea6a225410022502edc69eb8cb2a62d1bf5584740eb4f77f05add3d66a25ef113c8ab92c160fdcb8417da75b3616f3b79f33987c93b024e17f5eef37b8e39537b9a66c754d041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "88c60f0d8310590fcbcfd9c4c3cecd7f01adfcaddd61fdbd84193a66c49bbb6cb726845e75e0134d9e67d395b7dc017a5d0b36fe4aca2d67463d0eebd9041fc0bf408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "88c80f0d8313ee0bcd6196df3dbf4a002a693f75040089403b7000b800298b46ffdc6c96e4593e94642a6a225410022500ddc69fb8db2a62d1bfc8c755850bed38eb9f7f03adacbbfde1cb63617229755dd9cdbd579f0e1e58074f2bfa61ed9277a2a03c78187dacd1b66c56d67b5d6fc4107fc5c4", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88cc0f0d8369c139d16196df3dbf4a002a693f75040089403b7000b801298b46ffe0cbca6c96e4593e94642a6a225410022500ddc69fb8d894c5a37f55850bed38eb5f7f02ade3a0ad74fd8dda4dfa0c4b59dd9b6eebd34c9bebe7c32739baf47b80ff37e3a30febc8905bb569f66ce49e6820c9c8", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "88d00f0d8365b783d56196e4593e94642a6a225410022502edc13f7197d4c5a37fe46c96e4593e94642a6a225410022502edc13f7197d4c5a37fd0cf5585134c89f77f7f02adbfb3a8fbec9bde1d99f3698f12dcf8681c3939072ea1c868f578ef0c5e649c689f564cd9e5af65b0d429a1820fcdcc0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 150, + "wire": "88d40f0d836db65ad96196e4593e94642a6a225410022500ddc69fb8dbaa62d1bfe8d3d2c9558513cd89d7ff7f01add969d236726e7b4c44bfab1acdc336995cc87359972dee9cebc08df2fe65cde56d9cf53d69f5eb44d85bd9041fd0cf", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "88d70f0d8365965cdc6196e4593e94642a6a225410022500edc033702253168dffebd6d56c96e4593e94642a6a225410022500edc033702253168dff558513c079e6bf7f02adab361c9413659821bdea2f1a6ff8efa3aba76bc5fede0dda610a6df1c7e438a6da9cd9252ecbdcdab21e134107d4d3", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "88db0f0d8365c701e06196e4593e94642a6a225410022500edc037719794c5a37fefdad96c96e4593e94642a6a225410022500edc0357196d4c5a37f558513c07597bf7f02ad6e5a39fe76374e0d368a79e5b23ac6e5ff58766675fbb9b55e75bc98e286fc535dce38ef4a28a5732e56bc4107d8d7d5", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "88df0f0d8365c643e46196e4593e94642a6a225410022500edc033704fa98b46fff36c96e4593e94642a6a225410022500edc033704fa98b46ffdfde558513c079c77f7f02ad7fda5de7d63f403b7565e127e539f86df1c713eeea271d2ef0bf4d1e7b76bb0d8e2dd6b2143a787eb3df1ec820dcdb", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "88e30f0d8369e643e86196e4593e94642a6a225410022500edc00ae34d298b46fff7e2e16c96e4593e94642a6a225410022500edc00ae34d298b46ff558413c07c227f02ac1d9554785a3a38cffaff2e5e4a1b3c07ae365ccfc7f6bb4bfb3ccde4e8ed6073dfaab5ebb75c5ae39e19a083e0df", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "885f87352398ac4c697f0f0d023731ed6196dd6d5f4a082a6a225410022500edc082e36da98b46ff7685dc5b3b96cf6c96df3dbf4a019532db52820040a00371b66e01d53168dfe9e85585085a69a1077f04ad3a78b73bfac037d63fbe9eb3b63469f46bfab477c0d12acb87be0e17b987b5ec9d6f6a0dda39e54615a5d9041fe6e50f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 156, + "wire": "885f87352398ac5754df0f0d8369b13df36196c361be94138a6a225410022504cdc641702053168dffc3edec6c96dc34fd281654d444a820044a001700cdc69d53168dff558571b65c71cf7f03aef6348bddba7515bd7fbaf466fc7f2b79326020b077c58f90bc64e48c556bd789cd3ca4fc749c93d735dcecec820febea", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "88c80f0d83699037f76196c361be940094d27eea080112817ee32d5c13aa62d1bfc7f1f06c96c361be940094d27eea080112817ae01db8d34a62d1bf5584719001ff7f02add7103123f689d6b67fcdba66a7471c9e6fedb113bd7b95ebb8f07e011a67c8ff2279cc8dae71af33dda50c3041efeeec", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "88cc0f0d8379903b408721eaa8a4498f5788ea52d6b0e83772ff6196df3dbf4a002a693f75040089403b7000b80754c5a37fcc6c96e4593e94642a6a225410022502fdc00ae09c53168dfff7f655850bed38e3ff7f03ac88389fd6dc59eabbe3ac5d5b85d7363444343d581623fcc5c1ccdaf5731f5e27e5923a07846916cb6df1041ff4f3", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "88cb0f0d8365e0bbc26196d07abe941094d444a820044a083704cdc0b4a62d1bffd05891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a05e535112a0801128215c137719694c5a37f55850800e3cf0b7f04ad8d6b39dfd708e5d25d778bcd9b307e6ee16c5bb1db1779ff4fc655b92cf836e3e71ec33ba745985dc96f1f10417caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 160, + "wire": "885f88352398ac74acb37f0f0d840b42705fcb6196c361be94138a6a225410022502fdc6dab817d4c5a37fd9c6c56c96c361be94138a6a225410022502fdc699b8d894c5a37f558571c71c0bbf7f05aebfceecce6cbda7a42ff1711bb1593f86bc35b37acb4dec9923ebd3a65fdcdd2b9cd5fad4b139f8db9835bde2083fc4c3", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "886196dc34fd280654d27eea0801128166e01ab8cb8a62d1bfdd4088f2b0e9f6b1a4583f9105f7777eb3a6ffe7e6c08330398758b97f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb6e73f8ff75fad3279fce32eaf7fecb576c1afdb666bcdb1f3af5fbab87563f5de86ba4ecc59578ccde6f1dc124ade197fdc62dba899ff7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab5f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f6c96df697e941054dc5ad410020502edc65db8d054c5a37f0f138cfe5a69e716748d8dc65a07f352848fd24a8f0f0d83136f834085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf64022d31", + "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" + } + ] + }, + { + "seqno": 162, + "wire": "88e50f0d836dc65fdc6196df697e94132a6a225410022502e5c64171b0298b46ffead7d66c96df697e94132a6a225410022502e5c64171b0a98b46ff55857d9780273f7f0fadd4e6d4ac4db973ebce7ebc6a92bd5eb149bede47cf91c8f5f636d4c5bec929c86e63f5931f0d71fbe71450c107d5d4", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "88e90f0d840b4fbef7e06196df697e94640a6a2254100225040b827ae01f53168dffee6c96df697e94640a6a2254100225040b827ae01f53168dffdcdb5585642f3ef3bf7f02aecf4a76357b1cd8bb2c9b40de1a30038d566afc3760439d1f9b7dd389e7ff70d9af161b3dc397572e9b21bfe2083fd9d8", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88f30f0d836d97c3e46196df697e94640a6a225410022504cdc13b71a0a98b46fff2dfde6c96c361be940bea6a225410022502edc69ab8d36a62d1bf5585640f082dff7f02adbafbceb5926d24e4e5fa223781655adf32638b2ede742de76c3f94c8b61f2245fd9d2967deaa75438b7390c107dddc408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 165, + "wire": "88f80f0d840b4e3c2fe96196df3dbf4a002a693f750400894002e36edc1054c5a37ff7e4e36c96df697e94640a6a2254100225041b8d35702da98b46ff5585105c6996ff7f03adcba4ddf4f2d72e8a2ff8ef9024b2baab1c29ddfaffaabb8160f5cba756d673532fa5abc29676801263d7b2083fe2e1", + "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" + } + ] + }, + { + "seqno": 166, + "wire": "885f87352398ac4c697f0f0d840b4d38f7ee6196df3dbf4a002a693f75040089403b7000b811298b46ff7685dc5b3b96cf6c96e4593e94134a6a225410022500cdc6c5700253168dffebea55850bed38e35f7f04adb628f74ad7593a10cdc3ea9bba386ea87a6f46efabbd74696bbd148fc3918bd63d83cdd4b79c8f51fb7e6c820fe8e70f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 167, + "wire": "885f87352398ac5754df0f0d840bac89fff46196df3dbf4a002a693f75040089403b7000b8dbaa62d1bfc3efee6c96c361be94101486bb1410022502fdc65fb8c814c5a37f55850bed3817ff7f03ad7b4d1b62d4ee3bd1c7ce4711cb9fe2078b2793e9d3f8cf5a8ecfe8f275edda6a71f3eacd8eeb0528be29e1820fedec", + "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" + } + ] + }, + { + "seqno": 168, + "wire": "88c20f0d836c4d3ff86196df3dbf4a042a6a2254100225042b8d3b700d298b46ffc7f3f26c96df3dbf4a05953716b504008940bf704e5c69b53168df55850bed884d8b7f02acd6cbce0646e4f6ef6c5bc2cf2cbc78211c40b3de62e387625ade9f53cdd31fef5bf3dfc38ca7bb59bc921820f1f0", + "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" + } + ] + }, + { + "seqno": 169, + "wire": "88ca6c96c361be94136a65b6a504008140bd7042b8d3ea62d1bf5f86497ca582211f7b8b84842d695b05443c86aa6fe85893aed8e8313e94a47e561cc581c132f3afbc10ff6496e4593e94085486d994101912807ee003704ea98b46ffef0f0d8313e067408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 170, + "wire": "88d06c96c361be9413ca6e2d6a0801128005c002e36e298b46ff5f911d75d0620d263d4c795ba0fb8d04b0d5a7c3ed5893aed8e8313e94a47e561cc581c640d3e279d6ff6496df697e94138a6a2254101912820dc6dfb811298b46ff6196dc34fd280654d27eea0801128166e01ab8cbaa62d1bf0f0d830b4e3bc3", + "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" + } + ] + }, + { + "seqno": 171, + "wire": "88d56c96df697e94640a6a225410022500cdc68371a714c5a37fc8c7f15893aed8e8313e94a47e561cc581c640d81c6dc77f6496e4593e9413aa6a2254101912800dc69db82694c5a37fc10f0d83682d83c6", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "88d86c96df697e941094d03f4a0801128072e341b8cbaa62d1bfcbcaf45893aed8e8313e94a47e561cc581c10596d9742e7f6496df697e940b2a65b685040644a019b817ee36ca98b46fc40f0d830b6f03c9", + "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" + } + ] + }, + { + "seqno": 173, + "wire": "88db6c96e4593e940baa65b6a504003ea05eb8272e34fa98b46fcecdf75893aed8e8313e94a47e561cc581c0b2cbedb6eb5f6496d07abe94089486bb141019128005c69ab810a98b46ffc70f0d03383536cc", + "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" + } + ] + }, + { + "seqno": 174, + "wire": "88de6c96df697e94640a6a2254100225002b8c8ae09c53168dffcbd0fa5893aed8e8313e94a47e561cc581c640db6ebedbbf6496e4593e9413aa6a22541019128172e019b8db2a62d1bf6196dc34fd280654d27eea0801128166e01ab8cb8a62d1bf0f0d8475a7dc6bd0", + "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" + } + ] + }, + { + "seqno": 175, + "wire": "88de0f0d8365b71ad06196dd6d5f4a082a6a225410022502fdc65db820a98b46ffe35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96e4593e940894dc5ad4100225022b8015c13ca62d1bff5585081f7dc65d7f1cade156be5a1fdf9817b9eb373bd8753b96ba66c42a706b90a9ed8e592244b8d3edd4ddbcee8937876267efb2083f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 176, + "wire": "88e60f0d83684e3bd86196df697e94640a6a225410022500d5c6dbb811298b46ffeb6c96c361be940894d444a820044a05fb8db7700fa98b46ffc6c5558565d69f71cf7f04ad2743e5d9ee69f2e0cbb0d26fb6ec84c5c5dee597be289a9502736fec5f9fb8f156ce569dc68edd62a79f686083c3c20f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 177, + "wire": "88ee6c96e4593e94642a6a225410022500ddc13371b794c5a37fdbe05a839bd9ab5893aed8e8313e94a47e561cc581c640d81c6c0cff6496e4593e9413aa6a2254101912800dc69cb820298b46ffdb0f0d85085b742f7fe0", + "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" + } + ] + }, + { + "seqno": 178, + "wire": "88f40f0d830840d7e06196c361be940bea6a225410022502fdc69cb80694c5a37ff3cdcc6c96e4593e940094cb6d4a0801028215c08ae05d53168dff5585089d0be1737f06acbdca7674d38a734966be06b39efca51e8f41ecff894f3cfa6cca4cb8d1577cf255f92ad3cb4f7d298b04d041cbca", + "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" + } + ] + }, + { + "seqno": 179, + "wire": "88f20f0d8371b75de46196df697e94132a6a225410022502edc6dfb8dbca62d1bff76c96df697e94132a6a225410022502edc6deb82714c5a37fd2d15583136c8b7f02ad9c5f8dd69bda8cee78ef5382fe9896c3d7ddbc3f19d4fcbfb8b53356dfd1f335a3e34f447ee5e251833510c107cfce0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 180, + "wire": "885f87352398ac4c697f0f0d03343639e96196d07abe941054d03f4a080112817ae36edc69953168df7685dc5b3b96cfd7d66c96df3dbf4a05d5340fd2820044a05cb8d02e34ea98b46f558475c7c42f7f04ac26fd33b2ecdc991ede7ee7045ea9d30cdb6caf1cc6cda7d74bd8f978e45acc667acbba9152697aded56ec820d5d4", + "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" + } + ] + }, + { + "seqno": 181, + "wire": "885f87352398ac5754df0f0d830b827bef6196df3dbf4a05d5340fd2820044a0017190dc6dc53168dfc3dcdb6c96df697e940b6a681fa50400894037700fdc65a53168df558465b7da6b7f03adcf30afc98b7fb3c4dc6f69f3d629d3bbb72770dd1559f974c4e133463d497bdd3fbcdc72be3e1eccd4b7a1820fdad9", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "88c20f0d03333536f36196e4593e940b8a681fa504008940bf71a15c69c53168dfc7e0dfc15586640e36dbee7f7f01ab0eac716cea6fc58f992ea388127d06587dbb1d39939fbede02274937e72f89e56ec271a3b76ea1d57e6820dd7f1d8fd06421496c3d2a1283db24b61ea4ff408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d014c5a37fcc4088f2b0e9f6b1a4583f9105f7777eb3a6ffe7e6c08330398758b97f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb6e73f8ff75fad3279fce32eaf7fecb576c1afdb666bcdb1f3af5fbab87563f5de86ba4ecc59578ccde6f1dc124ade197fdc62dba899ff7b9384842d695b05443c86aa6fae082d8b43316a4fdd5f8b1d75d0620d263d4c7441ea0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f6c96df697e941054dc5ad410020502edc65db8d054c5a37f0f138cfe5a69e716748d8dc65a07f352848fd24a8f0f0d83136f834085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf64022d31408cf2b0e9f752d617b5a5424d279a03a02b6f904b09b8dd582128967dc69d582179b9412940db8fff", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "88cad8c9c8c7c6e5c50f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc4c30f138cfe5a69e716748d8dc65a07f3c20f0d83136f83c1c0bf7e9903a2765209c584dc6eac10944b471880b12579a1b62745189b", + "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" + } + ] + }, + { + "seqno": 185, + "wire": "885f88352398ac74acb37f0f0d8369e79b408721eaa8a4498f5788ea52d6b0e83772ff6196dc34fd280654d27eea0801128076e001700ca98b46ffdcf5f46c96df697e9403aa436cca080112806ae32ddc13ca62d1bf5584105e75df7f14adc959ec9706f4e1bde616fbb418e1ad6aeff4bf7b5b44e5466f1d4e3d58bbf7ef679dc1d1e03ebbf0bb462d9041f3f2", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "88e10f0d830b6d33c26196df697e940854dc5ad410022502cdc002e000a62d1bffe05891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96c361be940094cb6d0a080102817ae045719754c5a37f558669b75f69e07f7f04ae59c4bdbb2f7d3767724fd4b367036db3a64e3daaab8e53618f0de5b66ec3e49db2f3b6efe59ef343cb9487d9041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf7f1b8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "88e90f0d03353932ca6196d07abe941094d444a820044a081700cdc6df53168dffe86c96df3dbf4a019532db52820040a00371976e36ea98b46fc6c555850802171a0f7f04ad7bbf2f77f09a50176e0935ee925a3073fda26e70faa6f7290d7f9d0f66eeee6bd161a010e7b7365c513439a083c3c20f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 188, + "wire": "88ed0f0d830b8d39ce6196df3dbf4a05c530963504008940397021b8dbca62d1bfecc9c86c96e4593e940b2a6a2254100205040b8d3b704153168dff5586109b75b0b82f7f02ad676c9927d92e7d4ffe6ad9846d3fcff0e903ab69c97f253828905e4f8b1b5f8fbcf0336f97c4388d3f79764107c7c6", + "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" + } + ] + }, + { + "seqno": 189, + "wire": "886c96e4593e94642a6a2254100225042b8cbb71b0a98b46ff6496e4593e9403aa693f75040089410ae32edc6c2a62d1bf5f911d75d0620d263d4c1c88ad6b0a8acf520b409221ea496a4ac9b0752252d8b16a21e435537f858cd50ecf5f0f0d830b6fb958a7a47e561cc581975f7df07d295db1d0627d2951d64d83a9129eca7e94a6d4256b0bdc741a41a4bf6196dc34fd280654d27eea0801128166e01ab8d054c5a37f4087aaa21ca4498f57842507417f7f1a88cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 190, + "wire": "886c96e4593e94642a6a2254100225040b8276e34153168dff6496e4593e9403aa693f750400894102e09db8d054c5a37fc5c40f0d830b6fb958a7a47e561cc58197441781f4a576c74189f4a54759360ea44a7b29fa529b5095ac2f71d0690692ffc3c2c1", + "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" + } + ] + }, + { + "seqno": 191, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d094c5a37f7685dc5b3b96cf7f2e9107ee3dffb76186fe6c1fa1ccd60c577939ed7f2db4f5976edc8f789d8f3aed235799aaefefb6f369fcdc1d581fd596d719d6c7e7541b272ceff203e4eb56e44d79ee5cac13f88d7f9fec5a839bd9ab5f87352398ac4c697f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffeceb0f138cfe5a69e716748d8dc65a07f3ea0f0d83136f83e9e8e7e5", + "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" + } + ] + }, + { + "seqno": 192, + "wire": "88c3c27f02910fee3072699ddfad3b0e8e2dbececbf8fff17f02b4f18b46de99a70eb4b0769aed8fa227c9deb77f726b48b3e67af7b2bac1d9ff6c512cde75f024dbf066bd0feddf745fc87ce72a7ff0c1c00f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffee", + "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" + } + ] + }, + { + "seqno": 193, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03343532c3c7", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "88bf5f87497ca589d34d1f0f0d03343830c4c8", + "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" + } + ] + }, + { + "seqno": 195, + "wire": "88e96c96e4593e94642a6a225410022502f5c65fb8dbca62d1bf6196c361be940094d27eea0801128215c102e34d298b46ff6496dc34fd280654d27eea0801128215c102e34d298b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d846996840f408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f55846d9032f75890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 196, + "wire": "8bcb0f0d830b6d33f0d0cfeae96c96c361be94089486d99410021502cdc699b8d32a62d1bf5584101a00bf7f1fac726ca71b91eaef85269b8549df7ba71c7d2d5b076cf1f2ab1e6f0e172ebbf21b16670e49a7b5d5b74449a083e8e7", + "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" + } + ] + }, + { + "seqno": 197, + "wire": "88d26c96df3dbf4a09a5340fd2820044a01fb8d33702153168dfcb7b8b84842d695b05443c86aa6fd15893aed8e8313e94a47e561cc581c1059138e3ccff6496d07abe940894cb6d0a080c8940bf71a7ee09b53168dfd70f0d8369e133f7", + "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" + } + ] + }, + { + "seqno": 198, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d3aa62d1bfd77f139105fc77b76b77662ddbf13a2c61d9af6ddf4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f97f14b5378a21c469b616bc9e6399c24f2fea7b7e1f162f0e77bbbe6f3c183d1fec7eb537fed29cd33bc89d395ddd66bc5fedd1f36f017d7f7b9384842d695b05443c86aa6fae082d8b43316a4fd85f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 199, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d3ca62d1bfde7f0592039a796f7b9c3cf77e5fddf98f0e0bbf8cffc47f04b5ff724dbcb46d6f5f7e8dc35eaaedaff5b23583f3d62bb572456c5e4ef3cf77b72fcb335a6dd92eefff7fbbb830f8b1dfc790f77ceec3ddc20f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc1", + "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" + } + ] + }, + { + "seqno": 200, + "wire": "885f88352398ac74acb37f0f0d83132fb37f2788ea52d6b0e83772ff6196dd6d5f4a32053716b50400894006e36ddc13ca62d1bfe35891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df697e940b6a5f29141000fa806ae001702fa98b46ff558513eebaeb807f14ad368c04370c1970a69874dbc27efbb95ba7666f1b1b73ce1d7c7d989ca4e83e19373b9afc5bb7341ef6335ec8207caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 201, + "wire": "88e60f0d03353939c66196c361be9413ca6e2d6a080112816ae045700fa98b46ffebc5c46c96df3dbf4a019532db52820040a00371915c0b8a62d1bf558564207196df7f04ac4e90822ceb6ae7cb02dd23a911d76a13c22aba975fb0e348a4c21161fd964f677b75f9dcf30fb86ecfe2083fc3c2", + "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" + } + ] + }, + { + "seqno": 202, + "wire": "88cb0f0d8365a6ddca6196df697e94640a6a225410022502e5c69ab8c814c5a37fefc9c86c96d07abe94038a436cca0801128015c0b571b754c5a37f558565913417bf7f02adaa1fdef676bc37807bbe3c7987070e51d34eae1937c84cf92fc97abc39c22f7aaf439a6dd2b5503c4b889b2083c7c6", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88cf0f0d83642eb5ce6196df3dbf4a01e5340ec50400894006e09ab8d814c5a37ff3cdcc6c96c361be940b6a6a225410020502d5c1377196d4c5a37f5586101d75d7df7b7f02ae3b5fb777ddf1c7362b2f6af30d25efef15d9256717e77f026b0459233b6cdb83c70cb1fe10582484dab47ad9041fcbca", + "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" + } + ] + }, + { + "seqno": 204, + "wire": "88f20f0d827001d26196dd6d5f4a32053716b504008940b371a6ee01d53168dff76c96df3dbf4a019532db52820040a00371966e34d298b46fd2d1558513ecb617837f02ad8b067a5d77f1df1df679d8f10951f86e5a2f07c5cb2d158f7397f0b9a45cbade1ecdde34fa26be17b0df6a1820cfce0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 205, + "wire": "88d70f0d8365a69cd66196df3dbf4a01b5328ea504008940b5702edc0814c5a37f7685dc5b3b96cfd6d50f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96df3dbf4a040a612c6a08010a800dc13b71a714c5a37f5586138175a79b7b7f03ac5b375b3c3561ad26c90c416ad5161362c5bfc75b337a9fbf4f20d04acc0dfedde14f2df7dccf0d3e31966820d4d3", + "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" + } + ] + }, + { + "seqno": 206, + "wire": "88dc0f0d8365d7d9db6196c361be94138a6a225410022502fdc0397191298b46ffc2dad96c96df697e9403aa436cca0801128066e01eb800a98b46ff558571c7da7dcf7f02adfc724f5b16eb7f25b49aae1db1794e25bbfabee97f5d02397e4cb509ba9e58019bac991ed58342da2ba0b34107d8d7", + "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" + } + ] + }, + { + "seqno": 207, + "wire": "885f87352398ac4c697f0f0d03363039e06196df697e94136a6e2d6a0801128172e00371b794c5a37fc7dfde6c96df3dbf4a019532db52820040a05bb8db5702d298b46f55866596de7dd07f7f03ad8e2ae191e2fe3563d8f9919e9c59927cd6f5cdd65f192ce7ed6f7cbb63e86ae5d14cf9776089d783384fb2083fdddc", + "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" + } + ] + }, + { + "seqno": 208, + "wire": "88e50f0d8365c6d9e46196e4593e940054c258d4100225002b8d39702d298b46ffcbe3e26c96d07abe941054d27eea08010a816ae059b827d4c5a37f5586132f3ccb616b7f02ad8fa27bd39f16b7333e293249c61724b7a09ef53f9eb66765eab2e8eba6f569d5c31136adde3a36b37e63cd041fe1e0", + "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" + } + ] + }, + { + "seqno": 209, + "wire": "88e90f0d83644e3de86196df697e94132a6a225410022502e5c08ae32f298b46ffcfe7e66c96d07abe941054d27eea08010a816ae059b8d3aa62d1bf55857d97c2c83f7f02add3d3f2f19cdf7d6927ae99347135db13efb5515fc097432e1a3a66f525fa6216abd7e1d7970688666fcd50c107e5e4", + "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" + } + ] + }, + { + "seqno": 210, + "wire": "88ed0f0d8313eeb5ec6196df697e94640a6a225410022500fdc69db81714c5a37fd3ebea6c96df697e94032a435d8a0801128105c102e05d53168dff558565b75a6c5f7f02adfd89a7d1d4fc0d45de2e4c2aa7cdc32feea0dedfdfdf5d7c31df8b75fe1e6cdd384a991ec5b99c3d6ae346c820e9e8", + "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" + } + ] + }, + { + "seqno": 211, + "wire": "88f10f0d83644d39f06196c361be94138a6a225410022500d5c037704ca98b46ffd7efee0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96df697e940094c258d410020504cdc13971b0298b46ff5585744cb6e37f7f02ad06e8f75149c27d9b4383f47aede9749675a85656e2d97c5598bcb5f4db96dfda7887f5c8f9f8f417567764107fedec", + "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" + } + ] + }, + { + "seqno": 212, + "wire": "88f50f0d8365c75df46196d07abe941094d444a820044a099b8d3d719754c5a37fdbf3f26c96d07abe941054d27eea08010a816ae05ab81794c5a37f55857df782e87f7f02afeb93f3f64879b786aae72dad39f9799ebbaed196fbf77df3b29cfcb793161fcd182eef6b8e7fcf5a6b28776bf1041ff1f0", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "885f88352398ac74acb37f0f0d83138007408721eaa8a4498f5788ea52d6b0e83772ff6196e4593e940b4a5f2914100215040b8215c6db53168dffe15891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96e4593e9413ca6e2d6a08010a807ae005719754c5a37f558613c06d9742cf7f06aee9247a5f2b4cfada0e99acb357ef0ab17ee4e188c2c57b2e3dd999a85c730efd2cfe6f77f3d2db7a3dabb69d90417caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 214, + "wire": "88e00f0d830b4f3fc66196e4593e940bca65b68504008940b57197ae01b53168dfe9c5c46c96c361be94034a65b6a50400814006e322b8d894c5a37f55857d9136e0197f04adfc678f8d95f2ab46bc7b2f3ba32edf0e6f5af8eee4ba3a111df0538b8b5a667fd63e0dcd74bd3a425f60921820c3c2", + "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" + } + ] + }, + { + "seqno": 215, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d3ca62d1bfed4088f2b0e9f6b1a4583f910de0f2683a7937bf9ddc7772e9fcbaee2f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb38469b7d17be536de098dc60523f9e3cb959c1fbe33b5b0cd9e1d2d33292afdde8ff64bb2d72ed6fccfcbf1a3b846a1c3d3a9ff7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9abea0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 216, + "wire": "88c4f37f04900803a1d06fca0fccd7f6c2c875bffbcbc37f03b47b63cd72e9c3d35dbcd57a92f5fcf59804d538b44d2d37aac22e9464911d6aeffba736cc9eb84e8fca0f96b06ce7927d7930e1f1c2c1ed0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc0", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d3ea62d1bff67f019106d7797eb9c7601acd7f6076e6bbbafe6fc67f01b535ef0def92a08784ce6ca825d496add50ffbcb835936f9a1b73df027e658796dd8effbab00bf72b54b7f9c1dbfca3b396efc732f4fc5c45f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc4", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "88d80f0d8369d701d76196c361be940bea6a225410022500fdc0bf719654c5a37f7685dc5b3b96cfd7d66c96c361be9413aa65b68504008940b571915c644a62d1bf55850b207db0bb7f10adf1545d5ec8d4cf39edff3c197f2ea8a933dfb5796fb67c54adcf0664f6adf8fdece04cfdc6e7a7c7af9729a083d5d4", + "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" + } + ] + }, + { + "seqno": 219, + "wire": "88dd0f0d8365969edc6196c361be940b4a6e2d6a080112816ae32e5c0094c5a37fc2dbda6c96c361be941014cb6d0a080112816ae32f5c0054c5a37f55856990b4d89e7f02adc38218b4fe13746d7398dbfbdfc443ec7b9fbe3a8d4adbddfd3e2f1774962593769671fa8f26fe93f40c7e2083d9d8", + "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" + } + ] + }, + { + "seqno": 220, + "wire": "885f87352398ac4c697f0f0d03353837e16196dc34fd282029a889504008940b77196ae09e53168dffc7e0df6c96df3dbf4a019532db52820040a05bb8db5702e298b46f5585088007042f7f03adef4e59d1d59c92f4f78b16c861338d16ebdaedce0ef91e77778c639f7e0e76ddc34536229345279fd5b243041fdedd", + "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" + } + ] + }, + { + "seqno": 221, + "wire": "88e60f0d836dc7c3e56196df697e9403ea6a225410022500d5c65bb826d4c5a37fcbe4e30f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96df3dbf4a05953716b504008940bb71a7ae05b53168df5585105f036e377f02ade06b496559b4f992c1a1976bc923ded64dec78b4ebe58747ee5fccfab279d70a28880f60c3b53e9fc3e7f61820e2e1", + "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" + } + ] + }, + { + "seqno": 222, + "wire": "88ea0f0d8369d71ae96196df697e940b8a6a225410022502e5c65ab826d4c5a37fcfe8e76c96df3dbf4a01a535112a0801128015c0bb719694c5a37f55850b6d09c1377f02aded6f79ca88f8f0afb02fb5db1feeb368fde1167bb79af30e08ead39db4e99729c7ee1c1a6a785e2be9ab0c3041e6e5", + "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" + } + ] + }, + { + "seqno": 223, + "wire": "88ca0f0d03353838ed6196c361be9413ca6e2d6a0801128115c65bb8cbea62d1bfd36c96df3dbf4a019532db52820040a00371a0dc1094c5a37fedec55856421105b0f7f02aedba52ccd975f5c7caee9dbbd1cf6ee058b76c19787bc65cde01e247b3ede03cd4ebe9b4f7624f9a7be6ea09a083feae90f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 224, + "wire": "88f20f0d8365c79df16196e4593e94136a65b68504008940b771a66e34e298b46fd7f0ef6c96c361be940b2a65b68504008940b571b05c03ea62d1bf558679d0b8f38d7f7f02aed7171a397a8afe47763f46aeec869ce7265f38aee2bda99f3161a268ba5f9e1f1abbeed5463f33cbd7a353c3041feeed", + "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" + } + ] + }, + { + "seqno": 225, + "wire": "885f88352398ac74acb37f0f0d836db69d408721eaa8a4498f5788ea52d6b0e83772ff6196e4593e941054d03b14100225040b800dc0894c5a37ffdd5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96e4593e941054d03b1410022502d5c69ab807d4c5a37f55860bedbcebc17b7f06ad9b8edfc45ea316eccf3b82f07d3983f160747ef6a5aee77dbd3856b6cfc92ccdcadb3884b7f26d1da06af788207caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 226, + "wire": "88c70f0d83680207c66196c361be940bea6a225410022500fdc0bd702da98b46ffe5c5c46c96dc34fd281654d444a820044a08371a15c6c0a62d1bff55850b207db7db7f04ada7bd791eedcbbe2c73c516f3f4e5cf23bc79d2418fc57944ec7555af281e3fbecef0a33fe65373f4485a9a083fc3c2", + "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" + } + ] + }, + { + "seqno": 227, + "wire": "88cb0f0d8369d71fca6196d07abe9403ca6a2254100225041b817ae32da98b46ffe9c9c86c96df697e94642a65b685040089403d71a7ee32ea98b46f55851082e3aeb77f02ad91ec593f43909bb97ee8bbf995ec68fd8bba50d7a46dc16e2c28d366abb0c46bad8ed753c357ef6b4bdb66c820c7c6", + "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" + } + ] + }, + { + "seqno": 228, + "wire": "88e40f0d830badbfce6196df3dbf4a09d53716b50400894006e09db82714c5a37fedcdcc6c96d07abe940894ca3a941000fa817ae05fb8cb8a62d1bf5586644cbce34d7f7f02ab8f7caeb538bf53b1316403e9736d3647ce659f74f1634a536a34e344eb68c51bd37085b0c3cdddfe26820fcbca", + "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" + } + ] + }, + { + "seqno": 229, + "wire": "88d30f0d840baeb41fd26196c361be940894d444a820044a05ab817ee05b53168dfff1d1d00f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96e4593e940bea681fa5040081403f71b0dc682a62d1bf55860bcfb8cb2f7f7f02aee1cfcbe197972e84d58f364d42f1cc4e70d3ce56f06ce7cf9353379396ace3f5e968ac673ddbdd366c47173c4107cfce", + "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" + } + ] + }, + { + "seqno": 230, + "wire": "88f46c96d07abe94138a681d8a0801128205c0bf700f298b46ff5f86497ca582211f7b8b84842d695b05443c86aa6f5a839bd9ab5893aed8e8313e94a47e561cc581c640e36e32c8bf6496df3dbf4a09e535112a080c8940bf704cdc69b53168df6196dc34fd280654d27eea0801128166e01ab8db2a62d1bf0f0d831044e7dd", + "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" + } + ] + }, + { + "seqno": 231, + "wire": "887685dc5b3b96cf6c96df697e940baa65b685040089403771a76e34da98b46fc5c4c35893aed8e8313e94a47e561cc581c13afb4e38e35f6496d07abe9413aa6e2d6a080c894082e342b8cbaa62d1bfc20f0d830b617be1", + "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" + } + ] + }, + { + "seqno": 232, + "wire": "88c16c97e4593e94034a693f7504003ea01cb8db571a694c5a37ffc8c7c65893aed8e8313e94a47e561cc581c0b2cbedbaeb3f6496d07abe94089486bb141019128005c69db8d38a62d1bfc50f0d83109e7be4", + "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" + } + ] + }, + { + "seqno": 233, + "wire": "88c46c96c361be941054dc5ad410022500edc643700253168dffcbcac95893aed8e8313e94a47e561cc581c138fbec81c0ff6496df3dbf4a05c53716b5040644a01fb8d3f702d298b46fc80f0d8313ad8be7", + "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" + } + ] + }, + { + "seqno": 234, + "wire": "88c76c96d07abe9413ea6a225410022500d5c0b3704ca98b46ffcecdcc5893aed8e8313e94a47e561cc581c640d01e79f73f6496d07abe94136a6a22541019128215c65fb8d3ea62d1bfcb0f0d840bc269ffea", + "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" + } + ] + }, + { + "seqno": 235, + "wire": "88eb0f0d03373936ea6196c361be940894d444a820044a04171a6ee05f53168dffcbe9e80f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcfd555850be07c2eb57f15ad7f4632072febbd76bbf9487ac4073174fcfcbbd344a88f9a23afce36da7f8503de7bfe19d69d546aaf2d534107e6e5", + "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" + } + ] + }, + { + "seqno": 236, + "wire": "886196dc34fd280654d27eea0801128166e01ab8d894c5a37fce4088f2b0e9f6b1a4583f90037cddd0db62db8b0f3c7c5ed1cd96834003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb23e2e59b6d41e5fefa74255c470d28d9aedbf9e9017b510deaf26fb35331c3388fcb78b8d85ae5f7463c3436816e70af0e76f7b9384842d695b05443c86aa6fae082d8b43316a4fd65f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f4085aec1cd48ff86a8eb10649cbf4086f2b2075ad5cd91ae73a4f148645740fd447aa2f058d064975886a8eb10649cbf408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934f64022d31", + "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" + } + ] + }, + { + "seqno": 237, + "wire": "885f88352398ac74acb37f0f0d83132dbd408721eaa8a4498f5788ea52d6b0e83772ff6196d07abe941054d27eea08010a816ae341b8d854c5a37fdc5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe941054d27eea08010a816ae059b827d4c5a37f55866400702cbc2f7f12adb36a4fbec2eb360d95732de08a78b16ffce77b8cb9269fc26c663ddefb37cf653b05fb8bd729915f19fbec820f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 238, + "wire": "88c70f0d83132d33c66196d07abe9413ca693f750400854002e320b8d054c5a37fe4c5c46c96df697e94038a435d8a0801028266e04171b794c5a37f558613ed81d71b177f04ad69de908b47eb5bbc357ef1bae9171f431f2a7c6fc74f6fc66ce02d1e37974cee94397dc5c0fc35d7cec1ec820fc3c2", + "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" + } + ] + }, + { + "seqno": 239, + "wire": "88cb0f0d83640dbfca6196df3dbf4a01b5328ea504008940b3704e5c13aa62d1bfe8c9c86c96df3dbf4a040a612c6a08010a800dc13b71a714c5a37f5586138175d7c0e77f02aee5cc7dfd64d84c309bf7a2cb7ecfd1a1fedbb65d5931f7a4b9d9e12fbef6dbb72e28888afd7efac1777fef7f1041c7c6", + "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" + } + ] + }, + { + "seqno": 240, + "wire": "88cf0f0d83081f07ce6196dc34fd280654d27eea0801128072e01bb800298b46ffeccdccc5558413617d9f7f01ad7b8df1bfbef6ddcef1cd28e1f327ad67d1e48cd5c1bc78e47563927bd174bbd296f1a6aa16e9d7475b77c3041fcac9", + "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" + } + ] + }, + { + "seqno": 241, + "wire": "885f87352398ac5754df0f0d03373330d26196e4593e94136a65b685040089408ae342b8d854c5a37ff0d1d06c96d07abe94642a651d4a08010a807ae001700fa98b46ff558579d13ae8857f03add967e63c3efc187a3b349d3e1cf3ec3e62c3e9ed583ccbb3c2237cbce6d333fe5b3caffaab9ce63532f69a083fcfce", + "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" + } + ] + }, + { + "seqno": 242, + "wire": "88d70f0d83089d0fd66196df3dbf4a01b5328ea504008940bf71b7ae084a62d1bff4d5d46c96d07abe941054d27eea08010a816ae059b8d3aa62d1bf558613816da65f0f7f02adf72da5d06d9da5d0e262c8ededc63ede5ef2b9946d0ef55b25f05d9fb4f9377edcff5ec7965abae22c90ec820fd3d2", + "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" + } + ] + }, + { + "seqno": 243, + "wire": "88db0f0d830b2cb3da6196e4593e9403ca612c6a0801128215c08ae09f53168dff7685dc5b3b96cfdad9ce5586132203ceb4d77f02adc19f062a6eded0c8ef2304578c9dd86df0dfec4f9f506ac9a7f43be47b862f03e4de5d9db54da66b23866f1041d7d6", + "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" + } + ] + }, + { + "seqno": 244, + "wire": "88df0f0d830b2e07de6196e4593e9403aa681d8a080112820dc68371a7d4c5a37fc1dddc0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96c361be9403aa6a225410021500e5c102e32e298b46ff5586101d7c2cbcd77f02acaf576352dd7d74e796a01f37933b92f61c14e1c25ab84e0d71e78b6bf9e37e7737d76e24813b6b6bdbdb2083dbda", + "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" + } + ] + }, + { + "seqno": 245, + "wire": "88e30f0d83640073e26196df3dbf4a059535112a08010a8005c6dfb810a98b46ffc5e1e06c96df697e940094c258d410020504cdc659b820298b46ff558665969e032d0b7f02acc4fdeba0d780493bfbff27bdd53b3c4d91b47272ca3bf429b20e8e9d9a67686794d4fef788b4dfdfb1bd9041dfde", + "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" + } + ] + }, + { + "seqno": 246, + "wire": "88e70f0d83640d87e66196df697e941094d27eea08010a820dc03571a0298b46ffc9e5e4cd558613efb620059f7f01ae7ae8abdfc8d77d76358cb7cdebcfe5f191feb7bdfe67c00ed272f7a2836a77be473f1af60c9af0c6eeacbbbc4107e2e1", + "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" + } + ] + }, + { + "seqno": 247, + "wire": "88ea0f0d8365d79ae96196df697e94134a651d4a0801128215c037700f298b46ffcce8e76c96c361be941054d03f4a0801028105c65ab8d34a62d1bf5586134d81b0bcdf7f02ac31bc1bb4c4e37b962889b51a075ee45e77dc69b6da01bdf2e9f4d69e90f5a38a23cb3fec73c7a75831f8820fe6e5", + "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" + } + ] + }, + { + "seqno": 248, + "wire": "88ee0f0d83134cbfed6196dd6d5f4a080a693f7504008540b371a7ae34053168dfd0eceb6c96e4593e9413ca6e2d6a08010a807ae005719754c5a37f558664016c0fbacf7f02add2cc576ee89f0f3659e711071e908ff4f2947b77f3e62ede66f3928f57fb76abd7bdf8cf7635b1ecd8d7586083eae9", + "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" + } + ] + }, + { + "seqno": 249, + "wire": "88f20f0d83640f3bf16196d07abe941094d444a820044a0417020b80654c5a37ffd4f0ef0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe94136a65b6850400854106e01eb82754c5a37f5585081a744f877f02aeaf86e8b7f6d6dfea76eae38afe2b76ac5bff9e006e9ef41b17bf66f1ab4fe9b6783f2d54f8d1651beadbc0db2083eeed", + "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" + } + ] + }, + { + "seqno": 250, + "wire": "88f60f0d8365975df56196d07abe941094d444a820044a04571b6ee01a53168dffd8f4f36c96c361be94036a65b6a504003ea05ab8d39700053168df558508197597c17f02ace0f6cf7468053ea1ab8a4b5557bd577b06065b878dda9fd6ef7e0f592f1bcb76932710bf6c585670341e1820f2f1", + "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" + } + ] + }, + { + "seqno": 251, + "wire": "885f87352398ac4c697f0f0d023433408721eaa8a4498f5788ea52d6b0e83772ff6196c361be9413ca6e2d6a0801128115c0b9702253168dffde5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a019532db52820040a05cb816ee32253168df5585642165910b7f06adf5b7462be1a3261b3ded74d7489ceeb7e68a38926bdcda3f66fbf9af83ddfd5de69e7927bf89af134b3cfe20837caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 252, + "wire": "885f88352398ac74acb37f0f0d83138cbfc76196df697e940854ca3a94100215022b8cb971a1298b46ffe7588ca47e561cc581c640e8800003c66c96df697e941054be522820040a081704cdc0bea62d1bff55866dd0bef34f8b7f06adcdc35acde5ab1ce959ae34bf0e46edce267bf2ed913be2d77a13effce73ee71de04dfcfd6333f8daec7a7c4107c5c4", + "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" + } + ] + }, + { + "seqno": 253, + "wire": "88cd0f0d023533cc6196dc34fd2827d4dc5ad410022502e5c699b80714c5a37fec6c96df3dbf4a019532db52820040a099b8115c684a62d1bfcccb5585640103e07b7f02ad7eac31c26d0fdfafcde649543145ca397971c17b174fdebd66a6f3974360afb98e2aff7817565ae9275cde2083c9c80f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 254, + "wire": "88c70f0d83089c73d06196df697e940b2a5f2914100215001b8066e34ca98b46fff0cfce6c96d07abe940894be522820042a08571905c1094c5a37ff558613c203ee3a1f7f02ad6bf3735a7637d130eb47e58f5bedbcfbb24e64b3cc7cf3ea19259bcefec3cb253362e1bb8978fe339db178820fcdcc0f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 255, + "wire": "88d50f0d03353439d46196d07abe940baa6e2d6a0801128072e04171a0a98b46fff4d3d26c96df3dbf4a019532db52820040a01ab8d06e05e53168df5586680f36e36cff7f02ad789a05823ddd85e741ff6986dec3dba6ac7c3f0edcb87075f1adf7d936a71ce5f9b5e26c9f9c9f83ef12d0c107d1d0", + "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" + } + ] + }, + { + "seqno": 256, + "wire": "885f87352398ac5754df0f0d8313207fd96196d07abe941094d444a820044a0017190dc69e53168dff7685dc5b3b96cfd9d86c96df697e940bca6e2d6a0801128266e00371a654c5a37f5585081e0bef397f04acc9159c91b7050b370ea8732495339cc4c35688741eaaf364f3bac0ddc461bb96bf58ac4df5b8e5a30c3e2083d7d6", + "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" + } + ] + }, + { + "seqno": 257, + "wire": "88c30f0d8369c79fde6196e4593e940814d444a820044a00171976e044a62d1bffc26c96c361be940b6a65b68504008540bf71a66e36fa98b46fdedd55851042f34e0b7f02acf796c0746bc907c6aed1a5dea5dc4f09a38907c77e8af36cf5aaac4e0a494ccc7785cea77f78707a7a764107dbda0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 258, + "wire": "88c70f0d03333034e26196c361be94134a436cca0801128266e34f5c65f53168dfc6e1e06c96c361be940bca65b68504003ca08571b6ae34e298b46f5586700fb6ebadff7f02add79a9eb696bbfd6f74e9cdc142ebbeb65bcede092b6416ff4b44e5fa33530f79c9e3ded463f5537564b364107fdfde", + "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" + } + ] + }, + { + "seqno": 259, + "wire": "88e70f0d83642f33e66196df3dbf4a09d53716b504008940337040b8d054c5a37fca6c96df3dbf4a019532db52820040a05cb8205c644a62d1bfe6e55585644c85e6d97f02add5e21f0eb3ee52cd4f28b663e6b75478e4309168de3f16bcfeacd94bdf0fe47fbe65ec7cdaf0396d381ad9041fe3e2", + "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" + } + ] + }, + { + "seqno": 260, + "wire": "88e10f0d03383539ea6196df3dbf4a002a693f7504008940b77196ae09c53168dfcee9e80f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96df697e941094d03f4a0801128076e32ddc032a62d1bf55850b8cbc27bf7f02ada252ecbd4ec5b3ef414728a9cf4f85b0116d1360bdb51874fabe38dc3eabfab49fbe9ad9cd77c0f95ba764107fe7e6", + "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" + } + ] + }, + { + "seqno": 261, + "wire": "88e50f0d03393034eec1d1eceb6c96df3dbf4a082a435d8a08010a807ee360b80794c5a37fc07f00ad97cb5d6de789a7719330f1e9e47c38cfc2be36ec7d1c8735eab2b398fe56e50a311723f1e7db6e4c3d7f61820fe9e80f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 262, + "wire": "88e70f0d03393838f0c3d3eeed6c96e4593e94085486bb1410022500fdc69fb8d894c5a37fc27f00acae4f7146e3e976bec2c3e76f9c17d9caff6973f2b62e3467ab74c967875b39e41644729a7013cc248f6cd041ebea", + "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" + } + ] + }, + { + "seqno": 263, + "wire": "88f30f0d8375a75df26196c361be940bea6a225410022502cdc03371a1298b46ffd6f1f06c96df3dbf4a019532db52820040a003700e5c0b2a62d1bf5585089f700e8b7f02afc95fe75f13e5c5cb863dba2af5b61d9c7279ed2cb90317ee0f5c96abdf0e766ee564b63db62e61b6dc5b6f5ed9041fefee", + "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" + } + ] + }, + { + "seqno": 264, + "wire": "88db0f0d827402f66196c361be940b4a6e2d6a080112816ee36cdc138a62d1bfda6c96e4593e940894d444a820042a0037190dc640a62d1bfff6f5558669903ef3cf7f7f02aec68c4e47949ef1f8f7d4c5c73514e1f7805b2f53ef3f9de3cfaff3f2a87d2da5b6d3ee3b7bd89fddb7bddef1041ff3f20f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 265, + "wire": "88df0f0d8375f799408721eaa8a4498f5788ea52d6b0e83772ff6196c361be940bea6a2254100225022b827ee09d53168dffdf5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96c361be940b6a65b68504008540bf71a6ae044a62d1bf5585089f7822777f05ad45efcd5a62665eee72b63ceedb9f7651e4ed5f1a2f4dd3215397d770cf14fa24c2d13985d927e4dc29b764107f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 266, + "wire": "88e80f0d84105b79dfc66196c361be940bea6a225410022500edc68571a7d4c5a37fe7c5c46c96df3dbf4a09d53716b504008940bd71a15c640a62d1bf55850b216d91377f04addef8f75bec98611e8d5ba805d971660edfd4f51478f2edc3dcb1b9e27c8f60f3f9ae92a1dd619b064b229a083fc3c2", + "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" + } + ] + }, + { + "seqno": 267, + "wire": "88ec0f0d840b4f01efca6196c361be940b4a6e2d6a080112817ee342b820298b46ffebc9c86c96dc34fd28012996da9410022502e5c13771b0a98b46ff5585684fb816da7f02ad07117bfcaa2d36630fa0445d86cb38fbe488dbe7bfd305da19e4f591fb739661479c2d7a9f861c3a3de89a083fc7c6408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 268, + "wire": "885f88352398ac74acb37f0f0d03393239d0e0f0cecd6c96dd6d5f4a080a65b6a5040081403f71a72e040a62d1bfdf7f02aeebbb771dd967e5c6d75d91d8ff6c1387f0ea7179853e7664cb9bcfbbbbaad1be35aef747e5dd5f97b8f7a6cd9041cbca0f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 269, + "wire": "886196dc34fd280654d27eea0801128166e01ab8db4a62d1bff358b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007f4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff4003703370c1acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7e94bdae0fe75ee84ea6bdd7cea6ae1b54dd0e85356fdaa5fddad4bdab6ff30f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813f4087aaa21ca4498f57842507417f0f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c77b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab0f0d820ba05f95497ca589d34d1f649c7620a98326ed4b3cf36fac1fca", + "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" + } + ] + }, + { + "seqno": 270, + "wire": "8b5f87497ca589d34d1f0f0d03323436dc4088f2b0e9f6b1a4585fb485eaf5170eff5ef952eb93fe70730cb9faec95a23fe3f6f6a943b30bfb5adf8baf4fcc192ad996b7251d9d7acc0e57418e5f04cd408cf2b0e9f6b585ed6950958d278c6ae819142fb8cbb7dd0bd7dbc9409ff2b0e9f6b52548d6e854a194ac7b0d31aa1d0b4a6a0ab4834956320ef3800f92100215821580f6f0bd7197ae32eae0003f7f408ef2b0e9f6b52548d6a646d69c689f971c71802f3318c6028df7db8da764210057df74407db1ff588aa47e561cc581e71a00016c96df3dbf4a320521b66504008940bd7002b82654c5a37f0f139afe4647c4ccb1b8dc6cb91ba57249431bcd9647c622963137fcff52848fd24a8f76868691fb3d5b9955850b6e81e17f7f12aed9fb949f99713b94cf78b5605f75e7ff63e50d43c7571d2b7e5de1d6daf0f38f1efa71cf8c98eccbd9dd6fec820f7caf0ae0500e46cbd18a49091c6d36478acb3246170231321702d3eb9283db24b61ea4af5152a7f57a83db261b0f527fbfdf", + "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" + } + ] + }, + { + "seqno": 271, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03343531cdd4", + "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" + } + ] + }, + { + "seqno": 272, + "wire": "887685dc5b3b96cf6c96c361be94036a6a225410022502ddc106e32ea98b46ffc07b8b84842d695b05443c86aa6fd05892aed8e8313e94a47e561cc581c13c2132dbc26497df3dbf4a32053716b5040644a05bb8cbb71b714c5a37ffd90f0d03383536ee", + "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" + } + ] + }, + { + "seqno": 273, + "wire": "88c26c96d07abe9413ea6a225410022500d5c08ae082a62d1bffc4c1d35893aed8e8313e94a47e561cc581c640cbccb6e3df6496d07abe94136a6a2254101912816ee32edc684a62d1bfdc0f0d8371f75ff1", + "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" + } + ] + }, + { + "seqno": 274, + "wire": "88c56c96e4593e940baa6a225410022502e5c03d704e298b46ffc7c4d65892aed8e8313e94a47e561cc581c13e270426836496df697e940894d444a820322502e5c03d71b6d4c5a37fdf0f0d830bce03f4", + "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" + } + ] + }, + { + "seqno": 275, + "wire": "88c86c96d07abe940bca681fa504003ea041700edc69a53168dfcac7d9588da47e561cc581b780db2cbccb7f6496d07abe9413aa6e2d6a080c894082e342b8cbaa62d1bfe20f0d827820f7408af2b10649cab5073f5b6b9bd19376e525b0f4a8492a58d48e62a171d23f67a9721e9b81001e07", + "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" + } + ] + }, + { + "seqno": 276, + "wire": "88ceda0f0d03353136dce3", + "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" + } + ] + }, + { + "seqno": 277, + "wire": "48826402768586b19272ff7f22c7acf4189eac2cb07f33a535dc61848e65c72525a245c87a58f0c918ad9ad7f34d1fcfd297b5c1fcebdd09d4d7baf9d4d5c36a9ba1d0a6adfb54bbc37297f76b521cf9d4bdab6ff30f1fbe9d29aee30c2171d23f67a961c88f4849695c87a58292967fc3490472c827c3201613e369668ac8161b2312cf82394842b6191e97e0be601c9496891721e90f0d033237355f95497ca589d34d1f6a1271d882a60320eb3cf36fac1fe7408721eaa8a4498f5788ea52d6b0e83772ff0f28d3a4b449120a84411cb209f0c80584f8da59a2b20586c8c4b3e08e5210ad8647a5fb2f9acd615106eb6afa500da9a07e941002ca8066e36fdc642a62d1bfeeb1a67818fb90f48cd54091ccb8e4a4b448b90f4fdf", + "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;" + } + ] + }, + { + "seqno": 278, + "wire": "88eb6c96df3dbf4a09d53716b504008940bd7042b806d4c5a37f6196c361be940094d27eea080112816ae34fdc138a62d1bf6496dc34fd280654d27eea080112816ae34fdc138a62d1bf4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d84136cbc0f408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5584780113df5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 279, + "wire": "88f0d9efeeedec0f1fed9d29aee30c2171d23f67a961c88f4849695c87a5835acff92403a47ecf52e43d3f030c1f0314000802565f95d6c637d969c6ca57840138f3856656c51904eb4dc641ca2948db6524b204a32b8d3a171d1bcc9491c6dfc1e892239e007c5500596c2fb4ebce81e71bf89084813feb0f28c11c8b5761bb8c9ea007da97cf48cd540b8e91fb3d4b0e447a424b4ae43d3f6a60f359ac2a20df3dbf4a002b651d4b080cbaa0017000b800a98b46ffb5358d33c0c7eae90f0d0235375f87352398ac4c697ff5", + "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" + } + ] + }, + { + "seqno": 280, + "wire": "88da6c96c361be9413ca6e2d6a080112807ae36ddc0b2a62d1bfdcd9eb5893aed8e8313e94a47e561cc581c13ce32c85a7bf6496df697e94036a6a2254101912807ee09ab801298b46fff40f0d840b8dbcf7ca", + "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" + } + ] + }, + { + "seqno": 281, + "wire": "88dd6c96e4593e94085486bb1410022502fdc037704d298b46ffdfdcee5892aed8e8313e94a47e561cc581c0ba17c0e3406496df697e94136a681fa5040644a08571b6ee32d298b46ff70f0d84081d685fcd", + "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" + } + ] + }, + { + "seqno": 282, + "wire": "88e06c96c361be94136a681fa5040089403571a72e05953168dfe2dff15892aed8e8313e94a47e561cc581c105c105e6856497c361be940b8a65b685040644a01bb8d3d71b754c5a37ff6196dc34fd280654d27eea0801128166e01ab8db6a62d1bf0f0d8365f701d1", + "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" + } + ] + }, + { + "seqno": 283, + "wire": "88e46c96c361be94138a6a225410022500fdc033704053168dffe6e3f55893aed8e8313e94a47e561cc581c640d3cdbee83f6496df697e94138a6a22541019128205c035704d298b46ff6196dc34fd280654d27eea0801128166e01ab8db4a62d1bf0f0d840b400bffd5", + "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" + } + ] + }, + { + "seqno": 284, + "wire": "886196dc34fd280654d27eea0801128166e01ab8db8a62d1bfe94088f2b0e9f6b1a4583f910b9fba2ebcf716c19b972d9f98767ee9db7f1aff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb306be0ff1d29eefb1cf1a67f36f8bfe316cbfeddeb8f9bd8b3cf64f1ec431082ec79250fa6311af6ad3eb2a534d09c13557c7fb7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9abd20f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 285, + "wire": "88c4408cf2b0e9f752d617b5a5424d27990806e94b2bcb09b8dd58212896188a059e8e423c379b8dc75bd4c1c00f0d023533", + "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" + } + ] + }, + { + "seqno": 286, + "wire": "88c5f07f05910b99b183885b771037fe7e6ce3bf687f7fc47f04b6731fa745fbb276bfda7c6fedf8f82f9ba7bdb263bf5efeef06acb9fd79c3fba2ec7d34e3eb1bddbf65bfa9df4d7fb75bb726fc3a3a53c3c25f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc2", + "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" + } + ] + }, + { + "seqno": 287, + "wire": "88d70f0d8310822fe06196df3dbf4a09d53716b50400894035700fdc0bca62d1bff45891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96e4593e94032a436cca08010a8205c65db8c894c5a37f5585644279f65e4089f2b0e9f6b12558d27fac2c56966e17b1d5eb102f620f9e59ecd378d77185179eb77f0a2358ac865df7bd88016717e1aeecafbb3341077caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 288, + "wire": "885f88352398ac74acb37f0f0d830b8dbde96196e4593e940b8a681fa504008940bb71a72e34ca98b46f7685dc5b3b96cfc7c60f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe941054d27eea08010a816ae059b827d4c5a37f55860b4eb6eb4fb37f06acb3a70e2ec782f46cca7fc4acd18014621069a3be898efd5aad770249a0b939fbf597772e5db4e9a2feaf1041c5c4", + "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" + } + ] + }, + { + "seqno": 289, + "wire": "88c30f0d840b8cb8d7ee6196e4593e940b4a5f291410021500cdc0bb719794c5a37fc26c96c361be94034a693f75040085413371a7ae34253168dfcccb558613c10b6265ef7f02acc8e7201f69b426ddb7ef5ffd2a72d8f5f4eaf3602ad13bdb2bcc27e924d8045d18b07871f3cda07ae49a083fc9c80f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 290, + "wire": "88c56c96e4593e940b2a65b68504008540bb702f5c6c0a62d1bf5f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6fd85892aed8e8313e94a47e561cc581c0b8013ee05c6496e4593e940894d03f4a080c89408ae09bb811298b46ffdf0f0d03353934f7", + "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" + } + ] + }, + { + "seqno": 291, + "wire": "88dfca7f189107e33a78edd70eec18b6f2e37b1e30e367de7f18b5ff724dbcb46d6f5f7e8dc35eaaedaff5b23583f3d62bb572456c5e4ef3cf77b72fcb335a6dd92eefff7fbbb830f8b1dfc790f77ceedddcd70f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffdb", + "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" + } + ] + }, + { + "seqno": 292, + "wire": "88ce0f0d8313e017408721eaa8a4498f5788ea52d6b0e83772ff6196dc34fd282754d444a820044a099b8cb5702253168dffced7d66c96c361be941014cb6d0a080112816ee36fdc680a62d1bf55856dc740d35f7f0aae8f9e7e44f7c9a9e23f6db9ff377afd9341d9ebd3723b70fdd3c8f8bf2ce39e6ee3c9c7b687b77e5940f59890c107d5d4", + "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" + } + ] + }, + { + "seqno": 293, + "wire": "88d30f0d83642db7c26196df3dbf4a09c532db42820044a01fb8172e32ca98b46fd2dbda6c96df3dbf4a05f532db42820044a05db8105c0894c5a37f558679c6d9740cff7f02acafce1ba5e9ed0d1f6cd4f6f3cc824394c7ba2d977ad468e9f5af3ecc523d83a7759e272a00d63d98b5a61820d9d80f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 294, + "wire": "88d70f0d8365b65cc66197dd6d5f4a09d5340fd2820044a01eb8d3571b754c5a37ffd6dfde6c96df3dbf4a05f5340fd2820042a05ab8d39704f298b46f55860b2f32fb6fbf7f02aeefbcfe7ac9c69ddfbb37038b26dbfba169af1063909ef467e7fbe22db830f3c5beef0a96c7adbc72c9096fc3041fdddc", + "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" + } + ] + }, + { + "seqno": 295, + "wire": "88db0f0d83642d33ca6196d07abe94038a436cca080112816ee36cdc65f53168dfdae3e26c96d07abe94038a436cca0801128066e32f5c0094c5a37f558675c75f69d77f7f02ac75b1789af8f0947d9ac9b3a1898cbdbd70367e793a60e8820d6abb9059ee88ed74d5f9a37befe87300a6820fe1e0", + "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" + } + ] + }, + { + "seqno": 296, + "wire": "88df0f0d8364407fce6196df697e9413ca612c6a0801128215c6d9b820a98b46ffdee7e66c96df3dbf4a082a6a225410020502fdc6c571a0298b46ff5586105a75e13edf7f02ade17e6d4f399e677ba23db6458f3fb047be2c4b4b6bb7b6c3d7adda6fc5a70c84a31e0f7e437b2d7b674e6f1041e5e40f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 297, + "wire": "88e30f0d83644107d26196dc34fd282754d444a820044a099b8d37700153168dffe2ebea0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96c361be941014cb6d0a080112816ee36fdc69953168df55856dc7197dbf7f02adb3070aeb188208fd65f5bf22778f6ec158b749fc70f17da20af66d5b7d8a1c59479e7e97bf62cfb05e1ff1041fe9e8", + "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" + } + ] + }, + { + "seqno": 298, + "wire": "886196dc34fd280654d27eea0801128166e01ab8db8a62d1bfe67f1a91060dd95f0ded0e6d79fdf8b96367665c5f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f97f1bb6d137fbf1cf659e928bb7eac78f37afda3169b3aed6f17be3a3f3bf5c96e5ebb5e707cd147bfdd6ddecbf8c60c1a9b85e207b8b2f56bf7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab5f87352398ac4c697f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 299, + "wire": "88bf0f0d841044f0bfde6196df3dbf4a002a693f750400894106e01fb8d32a62d1bfee5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a002a693f750400894106e01fb8c854c5a37f55850b4cba16bf7f0caee987b79d35eacd91cc7cb5f6de866c1e7c9b66ab292d6716d2e1db9d9d1d0d1f04bf0ebf0eed7ef4bef4f6d9041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 300, + "wire": "88c70f0d03343339e66196dc34fd282029a889504008940bf702f5c136a62d1bfff6c5c46c96df3dbf4a019532db52820040a05cb8172e05d53168df5585085e742fb37f04ad6cb53ddd3a8003efd3b7cb7d11eb2f3f3e2dd7a3071b659997b2ebc9d5db7d263fd361d2ebbdf826e9a39a083fc3c20f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 301, + "wire": "886196dc34fd280654d27eea0801128166e01ab8dbaa62d1bf7685dc5b3b96cf7f13900c375ad78c50be1d98d9e79728b95efdd27f12b4e2df8fc03eff5dcf37f85e3d5a72bfd9bbe3749d26cde43c87e2adf97af6e699dbf5d4d54ad16973f7b4da68fdeafe6628d71fafd1d05f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffcf", + "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" + } + ] + }, + { + "seqno": 302, + "wire": "88d00f0d023637ef6196d07abe941094d444a820044a01bb8d82e09d53168dffc2cecd6c96df3dbf4a019532db52820040a05cb8172e05a53168df5585081c13ce877f07ad2e4afacddb6e2ebe87bf935af767413bd83479b6fa34332b5a7259af9f7738e40a3f5316498de7566d3143041fcccb0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 303, + "wire": "88d40f0d03383631f36196c361be940bea6a225410022500edc139704fa98b46ffc66c96dc34fd282694d27eea0800754033700d5c0054c5a37fd3d255850b2171903f7f02ad6f45df19fbe5c0ce06fbcc0eb3f3c155bcbf1cdb8bdded49f52e1a79f3f42aadf69c83f59dfd40ac7800786083d0cf0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 304, + "wire": "88d80f0d023433408721eaa8a4498f5788ea52d6b0e83772ff6196df697e94132a6a225410022500fdc08ae32ea98b46ffcbd7d66c96c361be94034a65b6a50400814006e34d5c0baa62d1bf55857dc699683f7f03ade4de0d31a496736abe3999b1dd37df6b2e5c7f84c1d3a5d2135bbb1d77deadc6fdd9c26e49d776a75ba31f8820d5d4", + "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" + } + ] + }, + { + "seqno": 305, + "wire": "88dd0f0d830b6fbdc26196dc34fd282029a889504008940b771b0dc03aa62d1bffcfdbda6c96df3dbf4a019532db52820040a05cb8172e09f53168df5585085f7dc6437f02aeab0f3df0dd86f1ead13bdbe297f31c3a713f158ce1e9eb84b56ebbcba792c62c5db2e64cc68a9d3b727e68f1041fd9d8408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 306, + "wire": "88e20f0d830b8dbbc76196df697e94136a6e2d6a0801128176e09eb8d814c5a37fd4e0df6c96df3dbf4a019532db52820040a05cb8172e32053168df55866596d975c7bf7f03ad42324bf9f97e3bb5bd66b882d08bc38ea8cfa7873fc6b21cf237b71c5b0aff277c6b0f98fafed6fe8bd3f8820fdedd", + "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" + } + ] + }, + { + "seqno": 307, + "wire": "885f88352398ac74acb37f0f0d83640167cc6196d07abe9413ca693f75040085410ae09ab806d4c5a37fd9e5e40f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe941054d27eea08010a816ae059b827d4c5a37f558613ed09e79b677f03adefa81b40fcffb79cdf57a9f469dfc5fe980b3462bf369a71adfa1cc3d86f45dd1a39d2f14f7538f8557fc4107fe3e2", + "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" + } + ] + }, + { + "seqno": 308, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03343535ee6196dc34fd280654d27eea0801128166e01ab8dbca62d1bf", + "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" + } + ] + }, + { + "seqno": 309, + "wire": "88c05f87497ca589d34d1f0f0d83136217f0bf", + "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" + } + ] + }, + { + "seqno": 310, + "wire": "88bf768586b19272ff4083928891831840d74085f2b4e7427f881840d297e00be2177f37e6bdae0fe61cf9d4bfbb5a97b56d535ee846a6bdd7c6a6ae1b54c9a6fa97b568534c3c54c9a77a99f55e5356fbdfcfd2959e8313d585960fe674a6bb8c3049d7ed6950931eaa476752a5721e963c3246076c8648800758ad9ae2bfeaa1d262673cc622fe69a3f97b8b84842d695b05443c86aa6f0f0d033535384088ea52d6b0e83772ff8f49a929ed4c01103e94a47e607d96bf7f1b88cc52d6b4341bb97f5f92497ca589d34d1f6a1271d882a60b532acf7f", + "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" + } + ] + }, + { + "seqno": 311, + "wire": "88c7c5c47f04871840ca97e01059c3c20f0d0237387f028f49a929ed4c01103e94a47e607da0ffc1c06496d07abe94138a65b68502fbeea806ee001700053168df5892ace84ac49ca4eb003e94aec2ac49ca4eb0034085aec1cd48ff86a8eb10649cbf0f28c7d79e089f75a7402582b3ccb2269a103ed42f9acd615106eb6afa500cada4fdd61002ca8166e01ab8dbca62d1bfed4ac699e063ed490f48cd540bf6b4a8498f5523b3a952b90f4f", + "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" + } + ] + }, + { + "seqno": 312, + "wire": "88d36c96e4593e940baa6a225410022502edc13f702d298b46ff6196dc34fd280654d27eea080112806ee32d5c0b6a62d1bf6496dd6d5f4a01a5349fba820044a01bb8cb5702da98b46f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d8413aeb2ef408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f558413a0699f5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 313, + "wire": "88d4d27f128318822f7f0c871882252fc0e85bd1d00f0d0234337f0c8f49a929ed4c01103e94a47e607dd67fcf5f87352398ac4c697fcccbca0f28c5c1ba07dd69d00960c8df6d2b03ed42f9acd61510722c9f4a09b5af948b0801654037700d5c6de53168dff6a5634cf031f6a487a466aa05fb5a5424c7aa91d9d4a95c87a7ef", + "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;" + } + ] + }, + { + "seqno": 314, + "wire": "88d8408cf2b0e9f752d617b5a5424d279a08998d979e7d61371bab042512cf0e5716186369a95f746c8cbfbf7b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab0f0d023533", + "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" + } + ] + }, + { + "seqno": 315, + "wire": "88dbfc7f3c910feeb7f0b58317e6bc41e41d7cef69cb9b7f18ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb38519c05e5a30b3fed9f1b897bd6d0478b6b2193767421fa80d9d9b706db38f872bda5c0fdf9b1e50f4cd87850f977cfbfa6dddc2c1c40f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 316, + "wire": "88df7685dc5b3b96cf7f03910b8f5de4d5dc7b3183f7f343b87f346bbbc27f02b5260ce11697d9ff74b5c8f83b614ebc92dec3c0dfed1eac9f33469f9998efb36e0c7daeed41269d9699dbd18f7fefd77bbbb8301bdfc6c5c80f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc1", + "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" + } + ] + }, + { + "seqno": 317, + "wire": "88e2c07f00910ebc21dbbb08736bfdc3bde8713db31b3fc47f00b5bba30617e87cd24dc9dcae676fac3c6f533670e70f1fc67569bf939b44636bbfed8f03bfc33ca9cf9a5c3aa7e924adc7f8fe59bc7fc8c75f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc4", + "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" + } + ] + }, + { + "seqno": 318, + "wire": "88cb0f0d0237367f1e88ea52d6b0e83772ff6196df697e94136a6e2d6a0801128166e321b8d32a62d1bfc55891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a019532db52820040a05bb8db371b0298b46f558665971d7df73f7f2fad292cf3abc7efacf9399f56476a0e3fd93a43560f556a8deb2addd257cfa2ef7b5fa16a4932d7fba3636986083f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 319, + "wire": "88f50f0d8313edb3c66196dd6d5f4a05a535112a0801128205c0b371b7d4c5a37fcdc5c40f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96c361be940bca681d8a08010a8266e360b82714c5a37f55850ba0109c077f04addbb6aea1249eb197a63f0fd35d967264b8e7e396fa744d784b0bf62d5efa877a65f58f647a315fdba0336c820fc3c2", + "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" + } + ] + }, + { + "seqno": 320, + "wire": "88f90f0d8313e07bca6196dc34fd280654d27eea0801128005c13f700153168dffd1c9c86c96d07abe941054d27eea08010a816ae059b8d3aa62d1bf558469b65b7b7f02ae938f1ed5f91f0ef34fb895b79d9e2f75ab4e377d5f059aff1a945b3270ed8f662767e535ff027f28afe2f5b2083fc7c60f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 321, + "wire": "885f88352398ac74acb37f0f0d83138f35cf6196d07abe9413ea6a225410022500fdc6c1700ca98b46ffd6cecd6c96df697e940094c258d410020504cdc13971b0298b46ff558569a65c7dcf7f03aed745f0c5e7a71b4eb73bdedd8bf46d78f5adccf878d47e993c012ff9e9f98eefac777b6117e97b646a38bb4d041fcccb0f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 322, + "wire": "88e10f0d03383739d36196dd6d5f4a01e532db42820044a0057196ee32d298b46fdad2d16c96df3dbf4a019532db52820040a05cb8115c69e53168df55860804c89f71bf7f02add3866e51cfae1c9af73908e2d508747e99adb978b2f609c597da4d6ead3934fe7bd0304789c150573a7a86083fd0cf0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 323, + "wire": "88e50f0d03383239d76196df697e9413ea693f7504008540b771a72e32d298b46fde6c96df3dbf4a019532db52820040a05cb8115c69f53168dfd7d6558613ecb8e3206f7f02ad03fab1121006f2707115fe5e70e88f368934d37dce5639ef87bfc99ccf475e29bd89e6b981d937e7ddcc1b2083d4d30f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 324, + "wire": "88e90f0d03383734db6196dc34fd282029a889504008940bb71a0dc69c53168dffe2dad9c55585085f13efb37f01aeb3c774f9b3844f7ad0d77c08a99cfe7238f6bd05bdbf4c23c82af25f8a7efaf50ff27cb0f0fcaf393876d5b2083fd7d6", + "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" + } + ] + }, + { + "seqno": 325, + "wire": "88ec0f0d03383339de6196dc34fd282794cb6d0a0801128172e36cdc6db53168dfe5dddcc8558679a6d969c6bf7f01ade99a2e2cef7a6bb3d5c7f1c1e2acdef495e6b2019f7b87d31eadf8af003a2ac22d2b7ee6e1877db6fbaa59a083dad9408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 326, + "wire": "88f00f0d03383733e26196df697e940094d444a820044a041700edc6c0a62d1bffe9cce1e0558513aeb6d09f7f02aef7adeb6fcee9f935db1754e1aef65d9466f5eeff7b47c28f0f6e9766bfd2f116acf0e18b09e8f1bd0eebe70c107fdedd", + "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" + } + ] + }, + { + "seqno": 327, + "wire": "88f30f0d03383339e56196df3dbf4a01a535112a0801128066e32f5c0b4a62d1bfece4e3cf5585138270006f7f01acf77b86f775b52490a2189bc1aa4fcdcb149cb7199bc39438afbfe24f0cbb47b2e6976741747e1a71f036c820e1e0", + "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" + } + ] + }, + { + "seqno": 328, + "wire": "88f60f0d03383239e86196dc34fd281794c258d4100225000b8cb771b754c5a37fefe7e66c96df3dbf4a019532db52820040a05cb8115c69c53168df5586109a109b685f7f02aed99b7de2cd7f0f6e3633f979ec792d316f46b63a33e1ad1287be5cbeafe69f7d4fdfc31e5367e5c7f3674cfb2083e5e40f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 329, + "wire": "885f87352398ac4c697f0f0d03383734ed6196dd6d5f4a09f532db42820044a00171966e32f298b46ff46c96df3dbf4a019532db52820040a05cb8115c69d53168dfedec558579a136f3c17f03adc3b2947edbe3a53b649bc70d0de3f3bfc89d4f316313bb35591cc1bf964d3ee2db643a86fbe13b79fbfaf1041feae90f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 330, + "wire": "886196dc34fd280654d27eea0801128166e01bb800a98b46fff87f36910e6c2e5ecb841fb0b3bdf068bd8b03df9f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f97f37b5c13dd2f5fce28c9c89edcc49c3c5f638f2cb8f47bd87e3fbc2db3fddecc0c1883243828cbd3b6fe55e2ab2db9b4a1e698933fe83b77b9384842d695b05443c86aa6fae082d8b43316a4f5a839bd9ab5f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 331, + "wire": "88ca0f0d03333934408721eaa8a4498f5788ea52d6b0e83772ff6196df697e94132a6a225410022502e5c69cb80794c5a37f7685dc5b3b96cf5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f6c96df3dbf4a019532db52820040a00371a72e36d298b46f55857d9742cb5f7f0eadcef9cd3e7eb3de462e1470599e9db0e7f1cbf19dfeadbbb3392b8898c93c774d7a94f085d65cfc7b3573cd041f7caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f0f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 332, + "wire": "88d40f0d03363237c76196df3dbf4a042a6a225410022502d5c659b820a98b46ffc6c5c46c96df3dbf4a019532db52820040a05cb816ee34d298b46f55850bef05f0077f04ad769a1aa30b8e76d9bfde4fcc382f7264e4fd6eac4ff7c78e5b79dfa7f2b90b77a67e3b87b361e8bde90f8a1820c3c2", + "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" + } + ] + }, + { + "seqno": 333, + "wire": "88d80f0d827041cb6196e4593e940814d444a820044a0437041b826d4c5a37ffca6c96df3dbf4a019532db52820040a05cb816ee34e298b46fcac95585101d7de0bb7f02aebc7ce4a777e61122dc39dcd976ad5d3a67f38384f2ba2e39a8b2ba3d5e6b6f3cb44ba76e095c5bf0c0aff3c4107fc7c60f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 334, + "wire": "885f88352398ac74acb37f0f0d83132dbdd06196df697e9413ea693f750400854006e362b8cbca62d1bfcfcecd0f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe941054d27eea08010a816ae059b827d4c5a37f558613ed05c65a6b7f03ad93699ee68e379bb32e869ea3c0eb6744e073663e363fe1cd5d81ae59990ecdbb731afd01d9bb26f67dc934107fcccb", + "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" + } + ] + }, + { + "seqno": 335, + "wire": "88e10f0d830b6fb5d46196dc34fd282029a88950400894082e05ab817d4c5a37ffd3d2d16c96df3dbf4a019532db52820040a05cb816ee36fa98b46f55850882fbcd337f02ad0c66b6d7f83eed68a39f1e70d3a30cf678dde355de7c7c7e1b3cde290e8db9b23b14eed02f74f3fdfdc03d9041d0cff0", + "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" + } + ] + }, + { + "seqno": 336, + "wire": "88e50f0d023433d86196e4593e94138a6e2d6a0801128215c0bd719754c5a37fd7d6d56c96df697e94136a6e2d6a0801128205c139704153168dff5586644d3efbcdff7f02ae97f190bbd6bd5874c8dfeefe37db93868b29dd80bcf6fbed4b5cabf57edcda7109ef595ad4f961efdc7ef878820fd4d30f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 337, + "wire": "88e90f0d83081c0fdc6196c361be940bea6a2254100225021b806ae05f53168dffdbdad96c96df3dbf4a019532db52820040a05cb817ae01b53168df55850b20644d337f02aea614fe76eb0f5bcd5fe87ae7bbef9e0e4dee7365767e379bd5ffdaf5fbf599fc07f77b39adeb261b2efb2b70c107d8d7", + "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" + } + ] + }, + { + "seqno": 338, + "wire": "88ed0f0d03383530e06196dc34fd2817d4d27eea08010a8015c00ae32253168dffdf6c96df3dbf4a019532db52820040a05cb8115c6c4a62d1bfdfde5586640275f75b077f02aee2ffb3dbdb547e9df7be4f0f690f0c37d677474d3bdcc880fbbce76c5eb51804efbbc6feda32fe87675f5378820fdcdb", + "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" + } + ] + }, + { + "seqno": 339, + "wire": "88d20f0d83136e07e46196d07abe941094d444a820044a00371a76e05b53168dffe3e2e1d15585081d75a71d7f01addc275ba7dedf529b07ef8c3bc9ae5f5c8053f3c6f8787e44dbefe0ef160bd3687238bceacf2f445648f1cd041fdfde0f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 340, + "wire": "88f40f0d03353634e76196df697e9413ea693f750400854086e36d5c69c53168dfe6e5e46c96c361be94034a65b6a50400814006e09db8c894c5a37f558613ecbc0105cf7f02abdaeee78f503bc9d438ff3cd86a561105fb3bc3d326a72995abc0e5b994e6c65987a05d3920da1b2d7b2083e3e2", + "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" + } + ] + }, + { + "seqno": 341, + "wire": "885f87352398ac4c697f0f0d830b8fbdec6196df697e9413ea693f75040085408ae083704053168dffebeae96c96df3dbf4a019532db52820040a003700cdc69b53168df558613ecbaf382177f03aee7df476bedf0eddb0e6f7e8328a9c24c7dbf1d1e889ac7e7553b7af3b50b6d9f94b7a4f5157da7d70e0f714d041fe8e70f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 342, + "wire": "88c20f0d03353538f06196dc34fd282029a88950400894086e32d5c65a53168dffefeeed6c96c361be94034a65b6a50400814006e09db81754c5a37f55850882d804f77f02ac2711b4d6cd02b5ec90dbc30bfb304b5cb51f7ccf0c1942f1b654ef89057f658b743ad2f37aed66c7d764107feceb408725453d44498f57842507417f", + "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" + } + ] + }, + { + "seqno": 343, + "wire": "88c70f0d83109c7bf56196dc34fd282794cb6d0a0801128015c641704253168dfff46c96df3dbf4a019532db52820040a0037000b81794c5a37ff4f3558579b03627817f03ad10b2dab66966932976f7fddd47e377d1267d51c73ebc1fa5bbba46b111d17ee41f2d06e3da98f475bacdd9a083f1f00f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 344, + "wire": "88cb0f0d820b81408721eaa8a4498f5788ea52d6b0e83772ff6196df697e94136a6e2d6a0801128205c13d71a714c5a37f7685dc5b3b96cf6c96df3dbf4a019532db52820040a05cb816ee09b53168df5891a47e561cc581c640e8800003eabb63a0c46496e4593e940bca681fa5040659500cdc659b820298b46f5586659684fbae7f7f06aded4ddd77fa8b2e6e23cbb6beeec2d533cd6e3d536e876084d7094f2ebd3aa7e64761fc47e89ecf87f342db20837caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 345, + "wire": "88f10f0d830b6e3bc76196dc34fd2827d4dc5ad4100225022b817ae34ca98b46ffc6c4c36c96df3dbf4a019532db52820040a05cb816ae01953168df5585640271d75f7f04ae7c758fd585db9fb67d3ddbddadfcda773782ddddf9b68d7c6fe33df9a3a33639b849d785e3f0bf865d77a3f1041fc3c2", + "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" + } + ] + }, + { + "seqno": 346, + "wire": "88d90f0d83101d6fcb6196e4593e9403ca612c6a0801128066e09bb8d814c5a37fcac8c76c96df3dbf4a019532db52820040a05cb817ee01f53168df5586132275c65b177f02acf2e9666a5e7cfaefe558f961c0d55a5dba91f6dbe8dfb2e9ee35bb9c8676b67f3dc729abec17d1debcdb2083c7c60f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 347, + "wire": "88dd0f0d830ba067cf6196df697e9413ea693f75040085403f71915c034a62d1bfce6c96df3dbf4a019532db52820040a05cb816ae32fa98b46fcdcc558613ecbcf3aebd7f02addd6c8eefd11038603f73f7cbe7978dd1cc53f3dff84879c3dc2d629e4dae333e5fdd5d0b778734774e6edb2083cbca0f138efe4015bf2dc7678263cfff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 348, + "wire": "88e10f0d8313800fd36196e4593e94136a65b685040089408ae36cdc65a53168dfd2d0cf6c96df3dbf4a019532db52820040a05cb8176e32e298b46f558579d13a079e7f02ada61ea0d5a9c2f7ba7bdafa61f3565ec6b31c4f773d229bc63c177d22f7e93b6c97617a501b2b67562be1d9041fcfce", + "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" + } + ] + }, + { + "seqno": 349, + "wire": "88e50f0d830b6f07d76196d07abe941094d444a820044a04371b76e36053168dffd6d4d36c96df3dbf4a019532db52820040a05cb8166e002a62d1bf5585081a03cc8b7f02acbe68e2c74929993cb4e2f7a538bbb385cfd87f0de720e6f5d701874e0bb4a4478f867303145eac8cf3f8820fd3d2e00f138efe401ff79b5b24c97f8e7ffa0ff3", + "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\"" + } + ] + }, + { + "seqno": 350, + "wire": "88e90f0d023434db6196dc34fd282029a8895040089400ae34ddc65b53168dffdad8d76c96df3dbf4a019532db52820040a05cb8166e34fa98b46f5585089a71d71d7f02aef1d2964b2f5d83877f1e5c4ffb93cfe73f195f9dd8b865e3b395d2faf1d62fc2f7aba72d4b0f13727e700dbe2083d7d6", + "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" + } + ] + }, + { + "seqno": 351, + "wire": "88dd6c96df3dbf4a044a681d8a08007d410ae081702da98b46ff5f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6f5a839bd9ab5893aed8e8313e94a47e561cc581c0b2cbcdb2f3ff6496dd6d5f4a042a435d8a080c894106e36d5c6c2a62d1bf6196dc34fd280654d27eea0801128166e01bb801298b46ff0f0d83085c77e60f138efe421fd67f7b9b14fdb3ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 352, + "wire": "88bee44088f2b0e9f6b1a4583f91069060deedffcda0fd06e7db7bf2fef17f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb3b38c7e336876de8f91ecdaf3f3a76c3c52d75e7b64d18bdf6c0fcee6ff44ff7c09f97dcf409dca9b487656814989aa005b3a557b9384842d695b05443c86aa6fae082d8b43316a4fc55f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f0f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 353, + "wire": "885f88352398ac74acb37f0f0d830b417fed6196d07abe941054d27eea08010a816ae05fb800a98b46ffeceae90f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96d07abe941054d27eea08010a816ae059b827d4c5a37f55866400704eb82f7f10ace2e881b676b8fe78cf58fbcc404decf35e87b925b5e2f4b56707bf84dd7f419b8f648afd252b99f6c70c107fe9e8", + "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" + } + ] + }, + { + "seqno": 354, + "wire": "88c20f0d8365c033f16196dc34fd280654d27eea0801128072e001702153168dfff0eeed6c96df697e94038a435d8a0801028266e04171b794c5a37f5584136d3e2f7f02ad976460a8d5e84fe65b79c793f7d6ecd76fed459d68cb6f777b43d733df8887ce99281f9b6d662d31bcf0a1820fedec0f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 355, + "wire": "885f87352398ac4c697f0f0d827020f66196e4593e940814d444a820044a01bb807ee01e53168dfff5f3f26c96df3dbf4a019532db52820040a00371905c03ca62d1bf5585104020b6df7f03adbc3fcf5539aa502745719f20b2eeda5dc799dd5fa59a9fcddd458cb8a206ffd5b17e66a8bab4b81f096b64107ff2f10f138efe421ff7251297859773ffd07f9f", + "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\"" + } + ] + }, + { + "seqno": 356, + "wire": "88cb0f0d83700e33408721eaa8a4498f5788ea52d6b0e83772ff6196df697e9413ca6e2d6a080102816ae05fb8d32a62d1bf7685dc5b3b96cf588ca47e561cc581c640e88000036496e4593e940bca681fa5040659500cdc659b820298b46f6c96dd6d5f4a0995340fd2820040a01db8c86e32253168df558671c138d322077f06acfc3375a2889bb62c30bd862279ac376699bcbb3b17afbe9eff2d8fd79ebd9cd463e36fbe51c5e6ba1d8e68207caf0ae050a065c0c8269b00da7df6e47c5238e06395c8de136590ab9283db24b61ea4af5152a7f57a83db261b0f527fbf4085f2b10649cb8ec664a92d87a542507b6496c3d49f0f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 357, + "wire": "88d50f0d8365e03dc76196d07abe94132a651d4a0801128205c6dbb827d4c5a37fc65891a47e561cc581c640e8800003eabb63a0c4c56c96e4593e9413ca6e2d6a08010a807ae005719754c5a37f5586134dbedbaeb57f05aee77b0793bdb2f7270cf46d336660f2cd247db119abb76c71d4dfd9df1e62ddf5c3574c3fbcbaf3262a7771f1041fc4c3", + "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" + } + ] + }, + { + "seqno": 358, + "wire": "88da0f0d8369d699cc6196df3dbf4a05c530963504008940bd71a66e32fa98b46fcbc2c96c96d07abe941054d27eea08010a816ae059b8d3aa62d1bf5586109b640079af7f02ae956fdd3cb2e5a25d9cb903d66f7b2476dbdb78651e8bbe658add0e9b18658f35dd326cd934de3d2d2e89f46c820fc8c7", + "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" + } + ] + }, + { + "seqno": 359, + "wire": "88de0f0d836da659d06196df697e94081486bb1410022500cdc10ae042a62d1bffcfc6cd6c96e4593e940b6a612c6a0801128172e34cdc03ea62d1bf55860baf85f75d177f02ad92234adbafeb01240f166af7c3f0df9f89bfbfd51b33e8f61fc5bdf0d7d4567a75fc5155c39fe2da41643b2083cccb", + "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" + } + ] + }, + { + "seqno": 360, + "wire": "88e20f0d8369a69fd46196c361be94132a681d8a0801128005c69bb8d32a62d1bfd3cad10f1394fe5a0f3fdcfd727fbe08cf16ece165b8bfe83fcf6c96c361be9403ea6e2d6a08010a8076e001704f298b46ff55860bed3cd32e037f02adfcc71feeed15a35e8c3cf5e2c65a3d76d9df99c2cb2b39c30bd57bcf96c969b6d8e58dea64888cf8cda5ef1041d0cf", + "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" + } + ] + }, + { + "seqno": 361, + "wire": "88e60f0d83680e37d86196df697e94136a6e2d6a0801128166e01db82754c5a37fd7ced56c96df3dbf4a01a530963504008140b971a66e36da98b46f558665971f69b73f7f02ad276efcd3fb826f734be373a787bf6d5d6df7b4dee7dc57c766726dc43d6dd556111bdf82931eef1b96bde2083fd4d30f1397fe590ad61900e1a079e2dd9db0022ddb820045ff41fe7f", + "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\"" + } + ] + }, + { + "seqno": 362, + "wire": "88ea0f0d8369d75edc6196e4593e940b4a6e2d6a08010a8176e360b817d4c5a37fdbd2d96c96d07abe94134a436cca08007d40b971a7ae084a62d1bf558665b7c4d89e6b7f02adf1f9cdfbf7e3e1663ca7ddced9746ba5382cdbb6d4f3eb5b2226af418c0ec5a49fb864e1b897c79f56dafc4107d8d70f13a2fe5a0ffb73f38c866e9cf16efc65c8b77365c8af6dfa07d03e9973e99722ffa0ff3f", + "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\"" + } + ] + }, + { + "seqno": 363, + "wire": "88de6c96e4593e941094dc5ad410020504cdc6dfb8d3ca62d1bf5f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6f5a839bd9ab5893aed8e8313e94a47e561cc581c0b2cb6f38d07f6496dd6d5f4a042a435d8a080c8940b5704fdc032a62d1bf6196dc34fd280654d27eea0801128166e01bb801298b46ff0f0d84109d701fe7", + "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" + } + ] + }, + { + "seqno": 364, + "wire": "886196dc34fd280654d27eea0801128166e01bb80654c5a37fe64088f2b0e9f6b1a4583f91068737e5c0ce1fde7bff36e9dbcdb08b9f4003703370ff12acf4189eac2cb07f33a535dc618f1e3c2e3a47ecf52e43d2c78648c56cd6bf9a68fe7eaf6b83f9bd0ea52feed6a67879297b86d521bfa14c9c613a9938df3a97b5693a9ab7eb3a9ab86d52fe0ce6535f0ba65356fda652ef0dca6bc7cd4d5a73a9c34e4535f0daa61c9a54bdab429a61e2a64d3bd4bf834297b4ef5376f854c7821535edc0a67d5794c5ab8a9ab7de53f94088f2b0e9f6b1a4585fb3b7ab09bfd270876dde993bc9dc18ba3f9785ec4c687cc6b2da317bd0f6a9f6f7e9c98ec49da9f5d85c12bb535c6af64f70d8e77b9384842d695b05443c86aa6fae082d8b43316a4fc6f10f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 365, + "wire": "88c3eb7f039105fd3c7161e38dabd85f7365dd2d6fd0ffc27f02b6ef83fd87d6e973f1629c16736c923a816993cf0d5ab570ef1f3bdc787ae77a4e9e49e63d2c97d6cdbd19d7e394f3dfeafffbf33ffbd9c1c9f40f28c74150831ea58d240175e59b7c4e09c12ccbae3ed32dfda958d33c0c7da921e919aa8171d23f67a9721e9fb50be6b3585441bed2fd2800ad94752c2032e2807ae001700153168dffc0", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_22.json b/http/http-client/src/test/resources/hpack-test-case/story_22.json new file mode 100644 index 0000000000..7250f49037 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_22.json @@ -0,0 +1,15857 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8c814c5a37f768586b19272ff588aa47e561cc581e71a003f6496dd6d5f4a01a5349fba820044a04571b72e32053168df6c96df697e940894ca3a9410020502cdc69eb800298b46ff0f138bfe5b0acd46d11d91f07f3f52848fd24a8f0f0d023831408721eaa8a4498f5788cc52d6b4341bb97f5f87497ca589d34d1f", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88c5c4c3c26c96d07abe94134a651d4a08010a810dc6c5700053168dff0f138bfe42c9566a466471d283f9c10f0d03333138c05f87497ca58ae819aa", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8c894c5a37f7686bbcb73015c1f0f0d83680cb55f90497ca589d34d1f649c7620a98268faff5885aec3771a4b6496dc34fd280654d27eea0801128115c6dcb8c894c5a37f5a839bd9ab0f28d3bb0e4bfc325f82eb8165c86f04182ee0042f61bd7c417305d71abcd5e0c2ddeb9871401fb50be6b3585441b869fa500cada4fdd6684a04571b72e32253168dff6a5634cf031f6a487a466aa05e319a4b5721e940037033709ebdae0fe54d5bf2297f76b52f6adaa64e30a9ab86d53269bea5ed5a14fe7fc8", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88c4cd6c96df3dbf4a080a651d4a08010a8076e05bb8cb6a62d1bf0f138ffe5c6cab34f8da095c6df659203f9fca0f0d830b8c83588ca47e561cc58190b6cb8000016496df697e940054d27eea0802128115c6dcb8c894c5a37fcb5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88c8d16c96df3dbf4a05f521aec5040089403f71b0dc1014c5a37f0f138efe5b8d66a3281b0c827197000fe7ce0f0d023931c1c0cdbf", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8cb2a62d1bfd3c40f28e8bb0e4bfc325f81f6a165cbe265f71e65c79dbacde7c4ebecc2215d84179f66e61c5007ed42f9acd615106eb6afa500cada4fdd60b2a04571b72e32ca98b46ffb5291f95873160642db2e0000fb52b1a67818fb5243d2335502f18cd25ab90f4fda9dcb620c7aa00f6c96df3dbf4a042a436cca08010a8076e34d5c642a62d1bf0f1390fe5b7647d6686365b95d7e37db203f9fd0c36496df697e940054d27eea0802128115c6dcb8cb2a62d1bf7b9384842d695b05443c86aa6fae082d8b43316a4fc80f0d83780007d15f901d75d0620d263d4c741f71a0961ab4ff", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88c2d7c80f28e9bb0e4bfc325f80227e1bf75f15d699bd86f36276f42ee1bafb376f5d7a1baf3d730e2803f6a17cd66b0a88375b57d280656d27eeb0595022b8db9719654c5a37fda948fcac398b03216d9700007da958d33c0c7da921e919aa8178c6692d5c87a7ed4ee5b1063d50076c96c361be940094d27eea0801128072e36d5c6c0a62d1bf0f1390fe5b6db6d668923b23e4191e13c0fe7fd4c7c1c0ca0f0d8375a7dfd3bf", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88c3d8c90f28e9bb0e4bfc325f82f5e1430c22870330e1640cc2fb4dde870bd81f7da6eede15fb9871401fb50be6b3585441badabe94032b693f7582ca8115c6dcb8cb2a62d1bfed4a47e561cc58190b6cb80003ed4ac699e063ed490f48cd540bc633496ae43d3f6a772d8831ea803f6c96df3dbf4a080a6e2d6a080112806ae322b8db6a62d1bf0f138ffe44e4a359a20c237e495c246407f3d5c8c2c1cb0f0d8365b79cd4c0", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88c4d9ca0f28e8bb0e4bfc325f81cbc1becb6f60699861be169903c0bc17b034fbc0659c2e86e61c5007ed42f9acd615106eb6afa500cada4fdd60b2a04571b72e32ca98b46ffb5291f95873160642db2e0000fb52b1a67818fb5243d2335502f18cd25ab90f4fda9dcb620c7aa00f6c96df3dbf4a320532db52820042a04171b72e36153168df0f138efe44dcab34370b190412342203f9d60f0d03363037c9c3d55f87352398ac5754df", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8cb4a62d1bfdc0f0d033134375f89352398ac7958c43d5fd1d0cf0f28d3bb0e4bfc325f82eb8165c86f04182ee0042f61bd7c417305d71abcd5e0c2ddeb9871401fb50be6b3585441b869fa500cada4fdd6684a04571b72e32253168dff6a5634cf031f6a487a466aa05e319a4b5721e9ced86c96d07abe94134a651d4a08010a810dc6c5700da98b46ff0f138ffe42c95669f1bee32378a065a07f3fdac6", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "880f28e9bb0e4bfc325f81dbace103b7e17705d75b78379c861861bc265f7ef030b4e3f730e2803f6a523f2b0e62c0c85b65c0001f6a17cd66b0a88375b57d280656d27eeb0595022b8db97197d4c5a37fda921e919aa8179c6708995c87a7ed4ac699e063ed4ee5b1063d5007cf5f91497ca589d34d1f649c7620a98386fc2b3d6496dc34fd280654d27eea0801128115c6dcb8cbea62d1bf5887a47e561cc5801f7b8b84842d695b05443c86aa6fd4798624f6d5d4b27f6196dc34fd280654d27eea0801128115c6dcb8cbea62d1bfda", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88c70f138afe44f3c065974226ff9fe06c96df697e940b4a612c6a0801128066e099b8cb8a62d1bf6496df697e9413ea6a22541002ca8115c6dcb8d014c5a37f588ba47e561cc58190840d00000f0d033739356196dc34fd280654d27eea0801128115c6dcb8d014c5a37fde", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88d50f138afe42fba07da71a6ddfe7e46c96df697e94105486d994100225022b817ee34ea98b46ffc1c00f0d023439bfdf", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88cc0f138afe596c0f0990b4d39fcfe56c96e4593e940894dc5ad410022500e5c6dfb8c814c5a37fc2c10f0d8369a71bc0e0", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "887688cbbb58980ae05c5f6196dc34fd280654d27eea0801128115c6dcb8d054c5a37f5f88352398ac74acb37f7f2988ea52d6b0e83772ff0f0d836df13d588ca47e561cc58190b6cb80003f0f1390fe59085c644dbc07c2d3ad3ae05f7bf96496dd6d5f4a0195349fba8200595002b807ee05b53168df6c96dc34fd280654d27eea0801128015c03b719654c5a37f", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88c4c3c2c10f0d84081b6c1fc00f1391fe42cbc165b79f132075f0b420040f7f3f6496c361be940054d27eea0801654082e36cdc69d53168df6c96df3dbf4a002a693f750400894039700ddc034a62d1bf", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "885f86497ca582211f0f1389fe5f7c2dbc069b0ff3f06c96c361be940094d27eea080112806ee01db80694c5a37fcdccd1e70f0d840840f07fcbeb", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88d80f138afe44f09c6de744cbdfcff16c96df697e940bca6e2d6a0801128072e36fdc13ca62d1bf6496df697e9413ea6a22541002ca8115c6dcb8d054c5a37fce0f0d830bc067c9ed", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88da0f138afe44f080271a7de67f9ff36c96df697e940bca6e2d6a0801128015c69bb81754c5a37fbfcf0f0d8365d033caee", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "88db0f1389fe5d75f005a6402fe7f46c96d07abe94038a436cca0801128105c0bb71b0298b46ffc0d00f0d83101b67cbef", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "885f8b497ca58e83ee3412c3569f0f1389fe5a65f03627dc73f9f66c96c361be940094d27eea080112806ee01db80654c5a37fd3d2d7ed0f0d8465e700ffd1f1", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88de0f138afe42d81913ecb6dbdfcff7bec2d2d7ed0f0d840b2175afcdf1", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88bf0f1389fe5d7c0269b7840fe7f7bed3d2d7ed0f0d846596d973d1f1", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88de0f138afe42165c65a6da033fcff76c96e4593e940baa6a225410022502edc03d700253168dff6496df697e9413ea6a22541002ca8115c6dcb8d32a62d1bfd40f0d8365d6436196dc34fd280654d27eea0801128115c6dcb8d32a62d1bff4", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88e10f138afe42f3c1784265b67f9ffa6c96df697e940b8a6a225410022502ddc13d719714c5a37fc0d6dbf10f0d830800efbff5", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88c30f1389fe5b6d9005a705fcfffb6c96c361be940bea6a225410022502ddc6dfb81754c5a37fc1d7dcf20f0d83105d7fc0f6", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "880f28e9bb0e4bfc325f81dbace103b7e17705d75b78379c861861bc265f7ef030b4e3f730e2803f6a523f2b0e62c0c85b65c0001f6a17cd66b0a88375b57d280656d27eeb0595022b8db97197d4c5a37fda921e919aa8179c6708995c87a7ed4ac699e063ed4ee5b1063d5007f1dfc1d7dcf2dbc0f6ed0f138afe44078417db784f7f3ffc6c96df697e940bca651d4a08010a8072e32fdc0094c5a37f0f0d023433", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88ee0f138afe44078417db784f7f3f52848fd24a8fbfc3d90f0d023433c2f8", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88c60f138afe42113e0699032dff3fbe6c96c361be940bea6a225410022502ddc6deb8d814c5a37fc4dadff50f0d830bee0bc3f9", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88d6c3e6d30f0d83081d730f138afe44cb2079d0becb3fcfbf6c96c361be940b2a65b6850400894033702edc684a62d1bf6496dc34fd281129947528200595021b8c86e01b53168dff588ca47e561cc5802db6d880007f", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88f30f138afe44079a69b71e719fe7c26c96df697e940bca651d4a08010a8066e005702fa98b46ffc8de0f0d023433c77686bbcb73015c1f", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8d34a62d1bf768fc17b568521ac649caa05702e1657075a839bd9abe65f87497ca589d34d1f", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "884085aec1cd48ff86a8eb10649cbfeafa0f138afe42f81b79d00421fe7fc96c96e4593e940bca693f7504003ea01fb8d35700fa98b46f6496dc34fd280654d27eea0801128115c6dcb8d34a62d1bf0f0d0130c4c5", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "887689aa6355e580ae05c2df6196dc34fd280654d27eea0801128115c6ddb81794c5a37ff0ece17f0386d27588324e5f5886a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff0f28a7cbbb06edd93569c97e01342038d34e3616aeb3780204379b03e17eebecb206c0cfda9ac699e063c7f0", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "884089f2b567f05b0b22d1fa87d78f5b0dae25d9588aa47e561cc5804dbe2003c76496df697e94038a693f75040089408ae36e5c69c53168dfdb0f28cca0e4802abb795ba156e855bb81585f55dbcadd0ab742addc0ac2ffda85f359ac2a20df697e94038b693f75840089408ae36e5c69c53168dff6a5634cf031f6a487a466aa05e719c2265721e9f3ca0f0d033638346196dc34fd280654d27eea0801128115c6dcb8d38a62d1bf7686a0d34e94d727", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "884084a4b2187f84a4b2187fe96496c361be94138a6a2254100225022b826ae05953168dff6c96dc34fd2826d486bb141000fa8076e01ab800298b46ffedc276841d6324e50f0d8379f7c5", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "887688aa6355e580ae05c16196dc34fd280654d27eea0801128115c6dcb8d3aa62d1bf5f911d75d0620d263d4c795ba0fb8d04b0d5a76c96df3dbf4a002a693f750400894082e001704053168dfffcf16496dc34fd280654d27eea0801128166e09cb8d3aa62d1bf5889a47e561cc5802f001f0f28c4348dbd001b2e9c145ee38723e47b1cbd42e70d10cd041f6a17cd66b0a8837da5fa50015b49fbac2128115c6dcb8d3aa62d1bfed490f48cd540dbcb90f4fda958d33c0c7f4003703370adacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe6f70daa437f429ab86d534eadaa6edf0a9a725ffe7d7", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "885f87352398ac5754df0f138afe42f3400b61032cff3fe16c96df697e940b4a612c6a0801128066e099b8cb8a62d1bf6496df697e9413ea6a22541002ca8115c6dcb8d3aa62d1bf588ba47e561cc58190840d00007b8b84842d695b05443c86aa6fdc0f0d8369f6dfc8df", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "88c20f138afe42265c0ba1132cff3fe5c1c0bfbedc0f0d8369b743c8df", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "880f28e9bb0e4bfc325f81dbace103b7e17705d75b78379c861861bc265f7ef030b4e3f730e2803f6a523f2b0e62c0c85b65c0001f6a17cd66b0a88375b57d280656d27eeb0595022b8db97197d4c5a37fda921e919aa8179c6708995c87a7ed4ac699e063ed4ee5b1063d50077f049ebdae0fe54d5bf2297f76b52f6adaa64e30a9ab86d53269bea5ed5a14fe7f5f91497ca589d34d1f649c7620a98386fc2b3dc2c1c0de798624f6d5d4b27fcbe25f89352398ac7958c43d5f0f1389fe5b71d0ba2138fff3e96c96df3dbf4a002a681d8a0801128015c64371b794c5a37f0f0d83085b07", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "886196dc34fd280654d27eea0801128115c6dab82754c5a37f7689aa6355e580ae05c20f5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559efc36c96df3dbf4a05c521b665040089403d71976e36d298b46f5888a47e561cc5819003e65501314084f2b7730fdd0ae1523e9352264571e0804a7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a2128f6e82e3c1036a7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a4d27a942cdc7c0f014feaf4952978649caa6e2d9dcb629c44b83fbf408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "886196d07abe941094d444a820044a01ab8015c65953168dffc55f87352398ac4c697f0f0d841099645f6c96d07abe94136a435d8a08010a8105c68371b754c5a37f588ba47e561cc5804dbe20001ff6c47f04dc0ae1526a44d02e3c1034a7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a2124f61719b8f040e29fd5e92a52f0c93954dc5b3b96c53889707f7f4a0570a9349ea50b371e0bcd29fd5e92a52f0c93954dc5b3b96c53889707f7c3", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "886196c361be94138a6a2254100225022b8d3f7190a98b46ffcac20f0d837d903f6c96d07abe94136a435d8a08010a807ae01db8d894c5a37fc1f9c77f01dc0ae1526a44d3371e081c53fabd254a5e19272a9b8b6772d8a7112e0fefe940ae1510947b75bb8f040d29fd5e92a52f0c93954dc5b3b96c53889707f7f4a0570a9349ea50b971f03c053fabd254a5e19272a9b8b6772d8a7112e0feffc6", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "887688aa6355e580ae25c16196dc34fd280654d27eea0801128115c6dcb8d3ea62d1bfded2c8d5ccc4f3", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "88c2cec60f0d841321719f6c96d07abe94136a435d8a08010a8105c69cb810a98b46ffc552848fd24a8fcc7f03dc0ae1526a44d02e3c10054feaf4952978649caa6e2d9dcb629c44b83fbfa502b8544251edd6ae3c0780a7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a4d27a942edc782f34a7f57a4a94bc324e553716cee5b14e225c1fdffcb", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "886196c361be94138a6a2254100225022b8d3f704153168dffd2ca0f0d8213c1c5c8c0ce7f00da0ae1526a44cbf71e0804a7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a2128f6e82e3cf29fd5e92a52f0c93954dc5b3b96c53889707f7f4a0570a9349ea5102e3c179a53fabd254a5e19272a9b8b6772d8a7112e0fefcd", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "886196df3dbf4a002a693f750400894035704fdc038a62d1bfd4cc0f0d033138336c96e4593e940854ca3a9410022500edc6c1719794c5a37fcbc3d17f01fa0ae1513d1330400b8f014feaf4952978649caa6e2d9dcb629c44b83fbfa502b8549a91340b8f040e29fd5e92a52f0c93954dc5b3b96c53889707f7f4a0570a884a3dbaddc7820754feaf4952978649caa6e2d9dcb629c44b83fbfa502b8549a4f5285eb8f32e014feaf4952978649caa6e2d9dcb629c44b83fbfd0", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88e86196dc34fd280654d27eea0801128115c6dcb8d814c5a37fcf6c96dd6d5f4a09a521aec5040085400ae04171a1298b46ffdcd26496dc34fd280654d27eea0801128166e09cb8d814c5a37fe60f28c4348dbd001b2e9c145ee38723e47b1cbd42e70d10cd041f6a17cd66b0a8837da5fa50015b49fbac2128115c6dcb8d3aa62d1bfed490f48cd540dbcb90f4fda958d33c0c7fe55a839bd9ab0f0d023335c8", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "887688aa6355e580ae25d9c2d30f0d0233356c96df697e940b8a6a225410022500cdc645700f298b46ffd6ca", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "886196df3dbf4a05e535112a0801128066e05db826d4c5a37fddd50f0d84085b69bf6c96d07abe94136a435d8a08010a807ee01eb8cb8a62d1bfd4ccda7f07dc0ae1526a44d02e3c103aa7f57a4a94bc324e553716cee5b14e225c1fdfd2815c2a2124f616deb8f040d29fd5e92a52f0c93954dc5b3b96c53889707f7f4a0570a9349ea50b971e0bcd29fd5e92a52f0c93954dc5b3b96c53889707f7d9", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "488264026196dc34fd280654d27eea0801128115c6dcb8d854c5a37f5f87497ca589d34d1fe67f1d88cc52d6b4341bb97f0f28cddf9305d87864bf0123132418ca1682c806091979a1b6eca1fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4ff0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1f40864d832148790b9365a085b71f65c7c2175d79965d65e0840c881f768586b19272ff", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "887689aa6355e580ae05c2df6196dc34fd280654d27eea0801128115c6ddb82694c5a37fecebe14085aec1cd48ff86d27588324e5f5886a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff0f28a7cbbb06edd93569c97e01342038d34e3616aeb3780204379b03e17eebecb206c0cfda9ac699e063cef1d80f1391e4c7f2d09e7160b2cbac89d7de740007f36c96c361be940bca681fa5040089403b71b7ee34ea98b46f0f0d83684f39", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "887688cbbb58980ae05c5f6196dc34fd280654d27eea0801128115c6dcb8d894c5a37f5f88352398ac74acb37fe80f0d836d96c5588ca47e561cc58190b6cb80003f0f1391fe5979b680db4cba169b13afb4fb2cff3f6496c361be940054d27eea080165403b71a15c65c53168df6c96df3dbf4a002a693f75040089403b702f5c69a53168df", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "88c2c1cc0f0d84101b6ddf6c96c361be940094d27eea080112800dc6dfb800298b46ff6496d07abe94032a5f2914100225022b8db971b1298b46ffe9e1cc", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "88eb0f138afe42d3ee09a138d37fcfe16c96dd6d5f4a05b521b66504008140b97000b800298b46ff6496d07abe940894dc5ad4100425022b8db971b1298b46ff588ca47e561cc58190840d0000070f0d830b6eb5c77686bbcb73015c1f", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "88c8c7d20f0d840b2e34d76c96dc34fd280654d27eea0801128066e32cdc6c2a62d1bfc3eee6d1", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88c9c8d30f0d837822176c96e4593e94642a6a225410022500e5c69fb8d814c5a37fc4efe7d2", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88d6d5798624f6d5d4b27fd57b8b84842d695b05443c86aa6f6c96dc34fd280654d27eea080112810dc13d704053168dffd5e0", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88cdccd70f0d840befb6e76c96dc34fd280654d27eea0801128072e32e5c138a62d1bfc8f3ebd6", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8db2a62d1bfcec2d9c16c96e4593e94642a6a225410022500edc1337191298b46ffd8e30f0d83684d036496d07abe94032a5f2914100225022b8db971b654c5a37f588ba47e561cc5804dbe20001fef", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "885f87352398ac4c697f0f138afe5a71a69a13aebffcfff0cc6496d07abe940894dc5ad4100425022b8db971b654c5a37fcb0f0d821321c3ca", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88bf0f1389fe5b642db6171a0ff3f1cdbecb0f0d03333339c3ca", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88c3768fc17b568521ac649caa05702e165707e8c8e0", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88c4d4df0f0d8375d69e6c96c361be940094d27eea0801128066e00571b7d4c5a37fc3c2f3de", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88d6d5c9e00f28cddf9305d87864bf0123132418ca1682c806091979a1b6eca1fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4ff0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1fdfde0f0d8413ed3ae76c96dc34fd280654d27eea0801128066e321b8d014c5a37fd1c3f4", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88c6d6cae1c96c96df3dbf4a002a693f7504008940377041b806d4c5a37fe0eb0f0d83759007c5c4f5", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88c7d7e20f0d8375f7d96c96df3dbf4a002a693f75040089403b702d5c0bea62d1bfc6c5f6e1", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88c8c40f0d0234336c96df3dbf4a05a535112a0801028105c082e34da98b46ff7f2588ea52d6b0e83772ffe352848fd24a8f", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88cb5f911d75d0620d263d4c795ba0fb8d04b0d5a76c96c361be9413ea6a225410020500e5c64171b714c5a37fd1c1d0e6cbcaf1", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88cdbf6c96e4593e940b4a6e2d6a08010a8072e059b801298b46ffd2c2d1e7cccbf2", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "88dfdee90f0d8465b719776c96e4593e94642a6a225410022500d5c10ae34053168dffdaccc2e8", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "88cfdfd3ea0f28cddf9305d87864bf0123132418ca1682c806091979a1b6eca1fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4ff0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1fe9e80f0d8369f7dd6c96df3dbf4a082a65b6a5040089403371b76e32ea98b46fcecdc3", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "88d0e0d4ebd36c96c361be9413ea65b6a50400894082e059b81714c5a37feaf50f0d83109c77cfcec4", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "88d1e1ec0f0d830b4f036c96d07abe941054d03f4a0801128076e36f5c038a62d1bfd0cfc5eb", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88d2e2ed0f0d8379f10b6c96d07abe941094d444a820044a019b820dc03aa62d1bffd1d0c6ec", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "88e30f138afe5a0ba20bad81907f3fc66c96df697e94132a6a2254100225020b8d3d704ea98b46ff0f0d837d97d9d476841d6324e5", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "88d55f87352398ac5754dff10f0d837c4fb56c96df697e94640a6a225410022500f5c0b9704e298b46ffd5d4caf0", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "88e8e7f20f0d8468027dff6c96c361be940094d27eea080112806ae01db800298b46ffe3d5cbf1", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8db4a62d1bfc1ddf4dc6c96c361be940094d27eea080112807ae32e5c69a53168dff35a839bd9ab0f0d8379b75f6496d07abe94032a5f2914100225022b8db971b694c5a37fd9cf", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88dcc4f70f0d840bce01bf6c96c361be940094d27eea080112807ae32e5c69953168dfbfdad0f6", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "88c2c5e1f80f28cddf9305d87864bf0123132418ca1682c806091979a1b6eca1fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4ff0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1ff7f60f0d841000fbffbebfdad0", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88c2c5f80f0d840bcf38dfc1bfdad0f6", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88c2c5f80f0d841002267fc1bfdad0f6", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "88dd5f86497ca582211f6c96c361be940094d27eea080112807ae321b81694c5a37fe3d3e2f8c2", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "48826402c5f90f1fa79d29aee30c5289978c6692d5c87a58a513314a268a41a4788a9a5135e3db527fc96c3d305289bfe3c30f0d82101c7f15842507417f5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88c7f27f0088cc52d6b4341bb97f0f0d840baf38ffc4c5e0d6fc", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88c8cbbe0f0d840bc0745fc7c5e0d6fc", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "88e3f30f0d84105913df6c96e4593e940bea651d4a08010a807ee05cb810a98b46ffd8768586b19272ffe3e2d8", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88cae1c00f0d830b4f076c96df697e94134a65b685040089403371b7ee09953168dfc8e3d9bf", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "88cbbfe9c90f0d821081c35f87497ca589d34d1f", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88f70f138afe597dc6da03c1683fcfda6c96df697e940b8a6a225410022500e5c6dab8dbca62d1bff1f00f0d8465f7df67f9ef", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "88cdd0c30f0d840844ebffc9cae5dbc1", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "88cdd0ecc3ebccc1cb0f0d84109979afcae5db", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "88cdd0ecc30f28cddf9305d87864bf0123132418ca1682c806091979a1b6eca1fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4ff0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1f40864d832148790b9365a085b71f65c7c2175d79965d65e0840c881fc20f0d84101f705fcacbe6dc", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88e9f9c40f0d84702d34d76c96e4593e94642a6a225410022500edc0b3702e298b46ffe8e7ddc3", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "88cfd2c50f0d840baeb22f6c96c361be940094d27eea080112807ee05cb82654c5a37fcde8dec4", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88ebdd6c96c361be94138a6a2254100225022b8dbd702ca98b46fff0e0efc5cf", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88ecdecbf0e0efc5eae9cf", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8dbaa62d1bfe9f1c8f06c96df697e940854d444a820042a01db8cbd700fa98b46ffc7d10f0d033939396496d07abe94032a5f2914100225022b8db971b754c5a37fece2", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "88c0d7ca0f0d8365f69f6c96d07abe9413aa436cca0801128072e32e5c6c0a62d1bfbfede3c9", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88c1d8cb0f0d83085b7b6c96d07abe94032a6e2d6a0801128066e34edc6dd53168dfc0eee4ca", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88c2d9cc0f0d830800f76c96d07abe9413aa436cca080112807ae09cb81754c5a37fc1efe5cb", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "88c3da6c96e4593e940b4a6e2d6a08010a8072e059b80714c5a37ff7e7f6ccc2f0d60f0d83640dbfe6", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "88c45f91497ca589d34d1f6a1271d882a60c57737ff8cf0f28d2df9305d862e1bb06ddfcf5e081d1886e3a1189c14616e374ae4ad3c17e3fb50be6b3585441be7b7e94642b5f291610040502ddc6dfb8dbea62d1bfed4ac699e063ed490f48cd540931631af18cd25ab90f4f0f1f989d29aee30c24c58c6bc633496ae43d2c1aa90be579d34d1f7f0a9365a0bacbce899640cbcf32e884cb410819103fce0f0d84101f705fd6d7f2e8f8d8", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "88c6bfd00f0d83085b7bc2c4f2e8cef9f87e9365a0bae3c07df740d3af05b75910821032207fd9", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "88c7de0f0d03363037ceeacfc5f3e9", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "88c7de0f0d8313e20f6c96df697e940baa681fa504008540397197ee004a62d1bfebd0c6f4ea", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "88c8df0f0d8313cc8bbeebd0c6f4ea", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88c8df0f0d83640dbfbeebd0c6f4ea", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88c8df0f0d8313c00fbeebd0c6f4ea", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88c8df0f0d8313e267c2ebd0c6f4ea", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "88c8dfd20f0d841004207f6c96df697e94640a6a225410022500edc6dcb806d4c5a37fc7f5ebd1", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8dbca62d1bfe10f0d8313cc83c0edd26496d07abe94032a5f2914100225022b8db971b794c5a37ff7ed", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88bfe20f0d8313cebbc1eed3bef7ed", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88bfe20f0d8313ee3bc5eed3bef7ed", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "88bff60f0d03313737c5eed3bef7ed", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "88bfc4d50f0d83085b7bc7c9f7edd3798624f6d5d4b27f7b8b84842d695b05443c86aa6f7f059265a0bc00be26df034cbce81979e104206440e0", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "88c2f90f0d83740e3bdcf1d6c1faf0", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88c2e56c96e4593e940b4a6e2d6a08010a8072e04571b0a98b46ffc1f2c0d7c2588ba47e561cc5804dbe20001fe20f0d03323838f2", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "88c45f87352398ac4c697f0f0d83784cb9cbf4d9c4bff3", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "886196dc34fd280654d27eea0801128115c6dcb8dbea62d1bfe90f0d8313cd0bc8f5da6496d07abe94032a5f2914100225022b8db971b7d4c5a37fc1f5", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "885f8b497ca58e83ee3412c3569f0f138afe5a13e1684d3adbbfcff66c96df3dbf4a082a65b6a5040089403d700d5c69c53168df6496d07abe940894dc5ad4100425022b8db971b7d4c5a37f588ca47e561cc58190840d000007c8e90f0d8365b6dec37686bbcb73015c1f", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "88de0f138afe5a132271f682fbdfcffa6c96df3dbf4a082a65b6a5040089403d700d5c69b53168dfc1c0caeb0f0d84081f007fc5bf", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "88c5768b1d6324e5502b857138b83f5f88352398ac74acb37f588ca47e561cc581a69e69f65f7f6496dd6d5f4a01c521aec50400b4a05bb8072e36f298b46f6c96df3dbf4a32152f948a08007d403d71976e002a62d1bfd0", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "88cac2c1588ca47e561cc581a009e001e6bf6496e4593e940894c258d41002d28176e361b8d32a62d1bf6c96c361be940b8a435d8a0801028066e01db8c854c5a37fd3", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "88cdc5c4588ca47e561cc58022742cb8267f6496dc34fd28c814d03b141002ca8172e320b8d094c5a37f6c96dc34fd281694ca3a9410022500ddc69fb8cb2a62d1bfd6", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "88d0c8c7588ca47e561cc581965b65f79c176496df697e94138a693f750400b2a05db8cb571a0a98b46f6c96dd6d5f4a05f53716b5040081403371a0dc65b53168dfd9", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "88d3cbca588ba47e561cc581a680d85f6f6496d07abe94134a5f2914100225022b8cb971b694c5a37f6c96df697e94134a65b68504008940b371976e01f53168dfdc", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "884084a4b2187f84a4b2187f588ca47e561cc58190b6cb80003f6496c361be94138a6a2254100225022b826ae05953168dff6c96dc34fd2826d486bb141000fa8076e01ab800298b46ffd1e276841d6324e50f0d8413a16dff", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "88dc0f138afe44271f784f36007f3f52848fd24a8f6c96df697e94134a436cca080102816ae09cb8d054c5a37fd9d8e25a839bd9ab0f0d03353731ded8", + "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" + } + ] + }, + { + "seqno": 130, + "wire": "88ded6d5588ca47e561cc5804d842175d0ff6496e4593e94105486d9941002ca806ae09cb8c814c5a37f6c96dc34fd2801290d762820042a01bb8dbb71b714c5a37fe7", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "88e1d9d8588ba47e561cc581f13ee8441f6496df697e940bea612c6a0801654033704fdc0014c5a37f6c96d07abe94009486bb1410022500edc6c571b714c5a37fea", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88e4dcdb588ca47e561cc581a0bc2001d6ff6496dd6d5f4a004a681d8a08016940b37197ae05a53168df6c96df3dbf4a042a681d8a080102810dc65ab827d4c5a37fed", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "88e7dfde588ba47e561cc58020101f101a6496c361be940054d03b141002ca8172e360b82654c5a37f6c96d07abe940894d03b1410022500ddc082e040a62d1bfff0", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "880f139728e3746091c8de748cc6d1641104e808065e0491ca27ff5893a47e561cc5801f4a536a12b585ee3a0d20d25fcb5f901d75d0620d263d4c741f71a0961ab4ff0f28c7c7a21bd7b570d3be006179b002fbe17da1061bf77ed4d634cf031f6a5f3d2335504f4af18cd25ab90f4fda983cd66b0a88375b57d281794ca3a941019794002e001700053168df4003703370c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f9408721eaa8a4498f57842507417f0f0d836dd75feed1", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "88eee6e5588ba47e561cc581e6c2db4f336496dd6d5f4a040a612c6a080165400ae08371a1298b46ff6c96c361be94101486bb14100225020b8076e32253168dfff7", + "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" + } + ] + }, + { + "seqno": 136, + "wire": "885895aec3771a4bf4a523f2b0e62c00fa52a3ac419272ff4085aec1cd48ff86a8eb10649cbff44090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbc40f0d0234336196dc34fd280654d27eea0801128115c6ddb800298b46ffd8", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "88be5f911d75d0620d263d4c795ba0fb8d04b0d5a77f0788cc52d6b4341bb97f0f0d83085b7b6c96c361be940094d27eea080112810dc6dab82794c5a37f6496d07abe94032a5f2914100225022b8dbb700053168dfffbdb768586b19272ff798624f6d5d4b27f7b8b84842d695b05443c86aa6f40864d832148790b9265a0bc00be26df034cbce81979e104206440dd", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "88c6c5c40f0d83085b7bc3c2588ba47e561cc5804dbe20001fe0c2c1c0bfde", + "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" + } + ] + }, + { + "seqno": 139, + "wire": "88c7c6c50f0d8365f69f6c96c361be940094d27eea0801128115c086e32e298b46ffc4bfe1c3c2c1df", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "880f28e8bb0e4bfc325f81b66e821680e3f089fbb82f5f0b9830b617df79abd7a1001bb9871401fb5291f958731607da700f000007da85f359ac2a20d07abe9413ab6a2256684a04571b76e004a62d1bfed490f48cd540bc633496ae43d3f6a5634cf031f6a772d8831ea8037f119ebdae0fe54d5bf2297f76b52f6adaa64e30a9ab86d53269bea5ed5a14fe7f5f8b497ca58e83ee3412c3569f0f138afe42e3ef38eb2dba2fe7e36c96df697e94640a6a225410022500f5c69fb8dbca62d1bf6496c361be940054c258d41002ca8115c6ddb801298b46ff588ba47e561cc581d75d700007c6e40f0d826c026196dc34fd280654d27eea0801128115c6ddb801298b46ffe8", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "880f28e9bb0e4bfc325f81b66e821680e3f089fbb82f5fbe07efde784fdec18216438305cc38a00fda948fcac398b03ed3807800003ed42f9acd61510683d5f4a09d5b5112b3425022b8dbb700253168dff6a487a466aa05e319a4b5721e9fb52b1a67818fb53b96c418f5401fc3c20f138afe44eb8f880dbc007f3fe7c1c0bfc7e50f0d8365d08bbee8", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "885f87352398ac5754df0f138afe42e0401684e3ef7f3fe86c96df3dbf4a082a65b6a5040089403d700d5c69d53168df6496d07abe940894dc5ad4100425022b8db971b7d4c5a37f588ca47e561cc58190840d000007cbe90f0d850b6f3e207f6196dc34fd280654d27eea0801128115c6dcb8dbea62d1bf7686bbcb73015c1f", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "886196dc34fd280654d27eea0801128115c6ddb80694c5a37f5f89352398ac7958c43d5fd40f0d83136d836c96df697e94640a681d8a080102807ee09bb8d814c5a37f6496d07abe94032a5f2914100225022b8dbb700d298b46ffcff1d3d2d1d0ef", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "886196dc34fd280654d27eea0801128115c6ddb80754c5a37f5f87352398ac4c697f6c96e4593e940b4a6e2d6a08010a8072e04371a1298b46ffd57f1a88ea52d6b0e83772ffd5d76496d07abe94032a5f2914100225022b8db971b794c5a37fd4f40f0d023433f6", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "88df5887a47e561cc5801fc20f138afe42f81b79d00421fe7ff76c96e4593e940bca693f7504003ea01fb8d35700fa98b46f6496dc34fd280654d27eea0801128115c6ddb80754c5a37f0f0d0130c5ca", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "88e3e2c4e1e70f0d023433c5fa", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "886196dc34fd280654d27eea0801128115c6ddb80794c5a37f5f86497ca582211f6c96df697e94640a6a225410022500fdc106e36e298b46ffddc5dcdefa6496d07abe94032a5f2914100225022b8dbb700f298b46ffdb", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88c1c86c96df3dbf4a002a693f7504008940b3704ddc0054c5a37fdfc7dee0bfdcfc0f0d0337383752848fd24a8f", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "88c3ca0f0d826c42bfc8e1c0ddbe", + "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" + } + ] + }, + { + "seqno": 150, + "wire": "88c3ce0f0d83136d836c96df697e94134a65b685040089403371b7ee09953168dfc9e2bfc1de", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "88c4768b1d6324e5502b857138b83f5f88352398ac74acb37f588ca47e561cc5802d3e203e173f6496df3dbf4a09b521aec50400b2a01bb8cbf700d298b46f6c96df3dbf4a09a5349fba820042a019b8cb3702da98b46fe6", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "88c9c2c1588ca47e561cc5804013a275c67f6496e4593e94138a65b6a50400b2a01ab8172e32153168df6c96dc34fd282654cb6d0a08010a8072e05eb821298b46ffe9", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "88ccc5c4588ba47e561cc581965e71e6996496e4593e940894be522820044a05db8d357190a98b46ff6c96c361be940baa436cca0801128066e085704253168dffec", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "88cfc8c7588aa47e561cc58190bef0036496e4593e9403aa693f75040089403771a76e01f53168df6c96dc34fd282754d444a820044a019b8176e01c53168dffef", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "88e40f138afe44f059038e34f37fcfcd6c96df3dbf4a044a436cca080102807ae34fdc6c4a62d1bf6496d07abe940894dc5ad4100425022b8dbb700f298b46ffe30f0d830b4f83d4e1", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "88d4d36c96c361be940094d27eea080112807ae321b81694c5a37ff2daf1f35a839bd9abd3f0", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "88d6d56c96c361be940094d27eea080112810dc03f702053168dfff4dcf3f5bfd4f1", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "88d7d6c0f4dcf3f5d4f1bf", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "88d7ded3f4dcf3f5d4f1bf0f0d8369d0b7d2", + "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" + } + ] + }, + { + "seqno": 160, + "wire": "88d7ded3f4dcf3f5d4f1bf0f0d836de69ed2", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "88d7d66c96df3dbf4a09f5340ec5040089403d7040b820298b46fff5ddf4f6d5f2c0", + "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" + } + ] + }, + { + "seqno": 162, + "wire": "88d8d1d0588ba47e561cc580217590bccf6496dc34fd281754d27eea0801128015c6c1702153168dff6c96dd6d5f4a01d535112a080112807ee043700253168dfff8", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "88dbd4d3588aa47e561cc5802c85c0356496d07abe94036a693f750400894006e320b8c894c5a37f6c96e4593e94642a6a2254100225021b8d82e05f53168dfffb", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88ded7d6588ba47e561cc5819036d3ce7f6496e4593e9403aa693f750400894006e34f5c65a53168df6c96dc34fd282754d444a820044a043702d5c0b8a62d1bff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 165, + "wire": "88e2dbda588ca47e561cc58020081c780fff6496df3dbf4a09e53096350400b2a045704cdc6dd53168df6c96e4593e940b4a681d8a080112816ae019b827d4c5a37fc1", + "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" + } + ] + }, + { + "seqno": 166, + "wire": "88e5dedd588ca47e561cc5802171c03410ff6496d07abe940bca681d8a0801654086e36edc0bea62d1bf6c96df697e9403aa612c6a080112816ae36e5c69b53168dfc4", + "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" + } + ] + }, + { + "seqno": 167, + "wire": "88e8e1e0588ba47e561cc5802cb6e3eebd6496d07abe940bea693f75040089403771b66e09c53168df6c96e4593e94032a6a225410022500cdc0357190a98b46ffc7", + "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" + } + ] + }, + { + "seqno": 168, + "wire": "88ebe4e3588ca47e561cc58020101a0b8dff6496c361be940054d03b141002ca816ee09cb8cb2a62d1bf6c96d07abe940894d03b1410022500edc6deb81754c5a37fca", + "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" + } + ] + }, + { + "seqno": 169, + "wire": "88eee7e6588ba47e561cc581f744e3e0736496dd6d5f4a09a53096350400b2a00571b15c0b4a62d1bf6c96c361be94132a681d8a080112807ee01cb8db6a62d1bfcd", + "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" + } + ] + }, + { + "seqno": 170, + "wire": "88f1eae9588ba47e561cc5804271b69b176496df3dbf4a09f5349fba820044a05eb816ae34053168df6c96e4593e940894dc5ad4100225002b8215c034a62d1bffd0", + "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" + } + ] + }, + { + "seqno": 171, + "wire": "88f4ec7f3a88cc52d6b4341bb97f0f0d8379d703dcf2588ba47e561cc5804dbe20001ff1768586b19272ffd37b8b84842d695b05443c86aa6fe0", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "88f85f87352398ac4c697ff5d57f0388ea52d6b0e83772ffc0c1f7c2e20f0d836de13df5", + "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" + } + ] + }, + { + "seqno": 173, + "wire": "88fabf0f0d8371a641f6bec1f7c2f5", + "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" + } + ] + }, + { + "seqno": 174, + "wire": "88fabff6d6bec0c1f7c2e20f0d8371e7c5f5", + "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" + } + ] + }, + { + "seqno": 175, + "wire": "88fabf0f0d8369c65f6c96c361be940094d27eea0801128105c082e32da98b46ffbfc2f6f8c3", + "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" + } + ] + }, + { + "seqno": 176, + "wire": "88fbc0f7d7bfc1c2f8c3e30f0d03383533f6", + "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" + } + ] + }, + { + "seqno": 177, + "wire": "88fbf4f3588ba47e561cc581c799684f356496d07abe941054ca3a941002ca816ee08371b1298b46ff6c96df697e9413ea681fa5040089403d700edc65f53168dfda", + "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" + } + ] + }, + { + "seqno": 178, + "wire": "886196dc34fd280654d27eea0801128115c6ddb80794c5a37ff8f7588ba47e561cc581e085d03adf6496df697e94036a612c6a0801654086e341b8d32a62d1bf6c96dd6d5f4a09f521aec504008940b7704edc6dd53168dfde", + "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" + } + ] + }, + { + "seqno": 179, + "wire": "88c1fbfa588ba47e561cc581c081e136df6496dd6d5f4a0595328ea50400b2a01bb8d06e09953168df6c96c361be940b6a65b6a50400894033704f5c65e53168dfe1", + "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" + } + ] + }, + { + "seqno": 180, + "wire": "88c4768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc580416dd69f736496e4593e9413ca693f75040089408ae05bb82694c5a37f6c96c361be940b4a6e2d6a080112816ae0817196d4c5a37fe6", + "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" + } + ] + }, + { + "seqno": 181, + "wire": "88c9c2c1588ba47e561cc581d680e040ff6496d07abe9413ca651d4a08016540397022b81754c5a37f6c96e4593e940b8a681fa5040089400ae09cb8d3ea62d1bfe9", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "88ccc5c4588ba47e561cc581b7dd7df6dc6496c361be940854ca3a941002ca817ae019b80694c5a37f6c96d07abe940bca65b6a5040089400ae34ddc0b6a62d1bfec", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "88cfc8c7588ba47e561cc580227c2c84206496d07abe94005486bb141002ca8266e36ddc65e53168df6c96d07abe9403ea651d4a080112816ee001700ea98b46ffef", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "88d25f86497ca582211f6c96c361be940094d27eea0801128166e32edc6c4a62d1bff1d9dbdc5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 185, + "wire": "88d5db0f0d8369c65f6c96df3dbf4a002a693f7504008940b3704ddc0054c5a37fdbde6496d07abe94032a5f2914100225022b8dbb700f298b46ffe052848fd24a8f", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "886196dc34fd280654d27eea0801128115c6ddb807d4c5a37fdfc1f6dee0e16496d07abe94032a5f2914100225022b8dbb700fa98b46ffe3c30f0d8365c759c0", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "88bfe00f0d03383334c2dfe2bee3c0", + "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" + } + ] + }, + { + "seqno": 188, + "wire": "88dac56c96c361be940094d27eea080112807ae321b81694c5a37ff8e0e2e3c4", + "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" + } + ] + }, + { + "seqno": 189, + "wire": "88c0e1dff8e0e2e3bfe4c40f0d836de13dc1", + "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" + } + ] + }, + { + "seqno": 190, + "wire": "88c0e10f0d03353836c3e0e3c1bfe4", + "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" + } + ] + }, + { + "seqno": 191, + "wire": "88c0e1c3f8e0e2e3bfe4c40f0d03353831c1", + "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" + } + ] + }, + { + "seqno": 192, + "wire": "88c0d4d3588ba47e561cc581b75a71b7d96496e4593e9403ea651d4a0801654006e059b8d094c5a37f6c96dc34fd282654cb6d4a0801128115c135700ca98b46fffb", + "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" + } + ] + }, + { + "seqno": 193, + "wire": "88c3d7d6588ba47e561cc581a6840101ef6496d07abe94134a5f291410022502e5c69db81754c5a37f6c96df697e94134a65b6850400894037702e5c6c4a62d1bf798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "88e25f91497ca589d34d1f6a1271d882a60c57737fed0f0d83136d836c96df697e94640a681d8a080102807ee09bb8d814c5a37f6496d07abe94032a5f2914100225022b8dbb700d298b46ffeecbedc1ec40864d832148790b9365a13aeb4279a6c0d01b0b4fb4d8021032207fcf0f28adf06416290bdcc42c00fb50be6b3585441badabe94032b693f758400b2a04571b76e01d53168dff6a5634cf031f", + "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=/" + } + ] + }, + { + "seqno": 195, + "wire": "88cbdfde588ba47e561cc581d6c0fb2cff6496d07abe940894d27eea080112806ee322b8d094c5a37f6c96e4593e940baa6a225410022500cdc69cb801298b46ffc5", + "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" + } + ] + }, + { + "seqno": 196, + "wire": "88e9e2e1588ca47e561cc58190ba069f79ff6496df697e94036a693f750400b2a04371b66e32ea98b46f6c96dd6d5f4a321535112a080102816ee01ab807d4c5a37fc8", + "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" + } + ] + }, + { + "seqno": 197, + "wire": "88d1e5e4588ba47e561cc5804d32e3adbb6496dc34fd2800a97ca4504008940bb71a7ee34e298b46ff6c96dc34fd280794dc5ad410022500cdc086e36d298b46ffcb", + "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" + } + ] + }, + { + "seqno": 198, + "wire": "88d4e8e7588aa47e561cc5802079b6416496dd6d5f4a01a5349fba820044a05fb806ee36fa98b46f6c96df3dbf4a002a693f750400894002e32fdc13ea62d1bfce", + "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" + } + ] + }, + { + "seqno": 199, + "wire": "88d7ebea588aa47e561cc581b0be21336496c361be9403ea693f7504008940b37020b8d894c5a37f6c96d07abe941094d444a820044a045704fdc69953168dffd1", + "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" + } + ] + }, + { + "seqno": 200, + "wire": "88daeeed588ba47e561cc581979c032f0b6496df697e940bca5f291410022500ddc0b971b0a98b46ff6c96d07abe94038a436cca080112806ae05db8d36a62d1bfd4", + "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" + } + ] + }, + { + "seqno": 201, + "wire": "88dd5f911d75d0620d263d4c795ba0fb8d04b0d5a76c96df697e94640a6a225410022500fdc106e36e298b46ffd6408721eaa8a4498f5788ea52d6b0e83772ff7b8b84842d695b05443c86aa6f768586b19272ffe1588ba47e561cc5804dbe20001fe7", + "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" + } + ] + }, + { + "seqno": 202, + "wire": "88e35f87352398ac4c697f0f0d8313c207e7c2c0e3bfe5", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88e4bee7dbc2c1c0e3bfe80f0d03363138e5", + "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" + } + ] + }, + { + "seqno": 204, + "wire": "88e4bee7dbc2c1c0e3bfe80f0d03353732e5", + "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" + } + ] + }, + { + "seqno": 205, + "wire": "88e4f8f7588ba47e561cc581f69f780d8b6496df3dbf4a082a612c6a0801654086e05eb800a98b46ff6c96e4593e9413ca681d8a0801128172e05bb82694c5a37fde", + "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" + } + ] + }, + { + "seqno": 206, + "wire": "88e7fbfa588ba47e561cc581a6da0bed8b6496e4593e94138a5f2914100225002b8cb9704153168dff6c96dc34fd2820a996da1410022500fdc65eb8d36a62d1bfe1", + "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" + } + ] + }, + { + "seqno": 207, + "wire": "88ea768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc581a79b69a6db6496dc34fd2827d4be522820044a05db826ae34d298b46ff6c96dc34fd281694cb6d0a080112806ae00371b794c5a37fe6", + "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" + } + ] + }, + { + "seqno": 208, + "wire": "88efc2c1588aa47e561cc580417597db6496df697e94038a693f750400894006e081704d298b46ff6c96d07abe9413ea6a2254100225022b8105c65f53168dffe9", + "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" + } + ] + }, + { + "seqno": 209, + "wire": "88f2c5c4588aa47e561cc581c03820b56496dc34fd281029a4fdd410022502cdc102e34ca98b46ff6c95dc34fd282029a8895040089408ae041700053168dfec", + "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" + } + ] + }, + { + "seqno": 210, + "wire": "88f5c8c7588ba47e561cc58020009a08816496e4593e9413aa612c6a08016540b3704ddc69f53168df6c96c361be940b8a681d8a080112810dc6dfb8d3ea62d1bfef", + "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" + } + ] + }, + { + "seqno": 211, + "wire": "88f8cbca588ba47e561cc581a6dd642f836496e4593e94138a5f2914100225021b8172e36fa98b46ff6c96c361be941014cb6d0a0801128172e05db82794c5a37ff2", + "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" + } + ] + }, + { + "seqno": 212, + "wire": "88fbcecd588ba47e561cc581e75d65c13d6496e4593e940b2a612c6a080165400ae01ab81754c5a37f6c96dc34fd28169486bb14100225020b8d0ae36253168dfff5", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "886196dc34fd280654d27eea0801128115c6ddb807d4c5a37fd90f0d84081b71cf6c96df3dbf4a002a693f7504008940b3704ddc0054c5a37fdedc6496d07abe94032a5f2914100225022b8dbb700fa98b46ffdc52848fd24a8f", + "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" + } + ] + }, + { + "seqno": 214, + "wire": "88c15f86497ca582211fc1fae1e0df5a839bd9abc1df", + "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" + } + ] + }, + { + "seqno": 215, + "wire": "88c3bf6c96c361be940094d27eea080112807ae321b81694c5a37f798624f6d5d4b27fe4e3e2c0c3e1", + "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" + } + ] + }, + { + "seqno": 216, + "wire": "88c5e66c96c361be940094d27eea080112810dc03f702053168dffbfe5e4e3c1", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "88c6e10f0d03383430c5e5e3c4e2c3", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "88c6e10f0d840800107fc5e5e3c4e2c3", + "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" + } + ] + }, + { + "seqno": 219, + "wire": "88c6e10f0d836df13fc5e5e3c3c4e2", + "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" + } + ] + }, + { + "seqno": 220, + "wire": "88c65f87352398ac5754df0f0d830bee83c1e6e4c5e3c4", + "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" + } + ] + }, + { + "seqno": 221, + "wire": "88c7be0f0d8313cebd6c96c361be940094d27eea0801128166e32edc6c4a62d1bfe7e5c6e4c5", + "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" + } + ] + }, + { + "seqno": 222, + "wire": "88c8bf0f0d83132e3bbee7e5c6e4c5", + "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" + } + ] + }, + { + "seqno": 223, + "wire": "88c8e30f0d033133386c96df697e94134a65b685040089403371b7ee09953168dfe8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 224, + "wire": "88c9c00f0d03323438c1e8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 225, + "wire": "88c9c00f0d03333430c1e8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 226, + "wire": "88c9c00f0d826c42c1e8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 227, + "wire": "88c9e40f0d83089e6bc1e8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 228, + "wire": "88c9e40f0d820b42c1e8e6c7e5c6", + "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" + } + ] + }, + { + "seqno": 229, + "wire": "88c9dddc588ba47e561cc5804f38ebcd3f6496df3dbf4a01c52f948a0801128176e32d5c65e53168df6c96e4593e9413ea436cca0801128066e342b810a98b46ffc5", + "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" + } + ] + }, + { + "seqno": 230, + "wire": "88cce0df588aa47e561cc581d684e89a6496d07abe940894d27eea0801128066e05bb8db2a62d1bf6c96e4593e940baa6a225410022500f5c0bf71a0a98b46ffc8", + "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" + } + ] + }, + { + "seqno": 231, + "wire": "88cfe3e2588ba47e561cc5802ebaebef876496dc34fd282694d27eea0801128015c6c1704053168dff6c96dd6d5f4a09953716b5040089403f7020b8d3aa62d1bfcb", + "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" + } + ] + }, + { + "seqno": 232, + "wire": "88d2e6e5588ba47e561cc581f704cbef7f6496e4593e940b4a693f7504008940b9702edc03aa62d1bf6c96c361be940894d444a820044a01cb8176e044a62d1bffce", + "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" + } + ] + }, + { + "seqno": 233, + "wire": "88d5e9e8588ca47e561cc5802d044dbafb5f6496df697e940b8a435d8a0801654002e34edc032a62d1bf6c96d07abe940894be522820042a059b8176e080a62d1bffd1", + "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" + } + ] + }, + { + "seqno": 234, + "wire": "88d8f9d2d1f7f6f5d30f0d03393534d6f4d5", + "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" + } + ] + }, + { + "seqno": 235, + "wire": "88d8eceb588aa47e561cc581a642d81c6496df3dbf4a01e5349fba820044a04571a7ae36da98b46f6c96e4593e94134a6a225410022502cdc0b3719754c5a37fd4", + "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" + } + ] + }, + { + "seqno": 236, + "wire": "88dbefee588ca47e561cc5802169e75e0b9f6496dc34fd281714d03b141002ca8115c002e34da98b46ff6c96dc34fd2810a984b1a820044a05ab8d3f71b754c5a37fd7", + "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" + } + ] + }, + { + "seqno": 237, + "wire": "88def2f1588ba47e561cc5804eb2f3edbd6496e4593e94036a5f291410022500ddc69cb82754c5a37f6c96dc34fd2800a9b8b5a820044a019b817ae32253168dffda", + "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" + } + ] + }, + { + "seqno": 238, + "wire": "88e1f5f4588ba47e561cc581b6dc71b0376496dd6d5f4a01c5328ea50400b2a099b8115c0b4a62d1bf6c96e4593e9413aa65b6a504008940b9704e5c6df53168dfdd", + "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" + } + ] + }, + { + "seqno": 239, + "wire": "88e45f87352398ac4c697f0f0d83640e336c96c361be940094d27eea0801128105c082e32e298b46ff408721eaa8a4498f5788ea52d6b0e83772ff768586b19272ffe6588ba47e561cc5804dbe20001fe6", + "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" + } + ] + }, + { + "seqno": 240, + "wire": "88e9e00f0d03353339e1c0bfe7bee6", + "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" + } + ] + }, + { + "seqno": 241, + "wire": "88e9c2e8e2c07b8b84842d695b05443c86aa6fc0e8bfe50f0d840ba2139fe7", + "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" + } + ] + }, + { + "seqno": 242, + "wire": "88eac30f0d03383333e9c1c0e8bfe7", + "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" + } + ] + }, + { + "seqno": 243, + "wire": "886196dc34fd280654d27eea0801128115c6ddb810298b46ffc40f0d827840eac2c1e86496d07abe94032a5f2914100225022b8dbb702053168dffc1", + "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" + } + ] + }, + { + "seqno": 244, + "wire": "88ece36c96e4593e940b4a6e2d6a08010a8072e04571a714c5a37fe6c4c1c3ebc2e80f0d8369f087ea", + "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" + } + ] + }, + { + "seqno": 245, + "wire": "88c0e40f0d830b2fb5e5c4c3bfc2ea", + "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" + } + ] + }, + { + "seqno": 246, + "wire": "88ede40f0d836dd745e7c4c3ebc2ea", + "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" + } + ] + }, + { + "seqno": 247, + "wire": "88edc6ece6c4c1c3ebc2e80f0d84081f6dafea", + "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" + } + ] + }, + { + "seqno": 248, + "wire": "88c0e40f0d03393934e5c4c3bfc2ea", + "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" + } + ] + }, + { + "seqno": 249, + "wire": "88ed768b1d6324e5502b857138b83f5f88352398ac74acb37f588ca47e561cc581b680d38d01bf6496df697e941094cb6d0a0801694006e360b8cb4a62d1bf6c96d07abe940054cb6d4a08007d4086e041702f298b46ffeb", + "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" + } + ] + }, + { + "seqno": 250, + "wire": "88c5c2c1588aa47e561cc581d03af3a16496dd6d5f4a042a693f7504008940bb7196ee002a62d1bf6c96df3dbf4a05e535112a0801128066e341b82754c5a37fee", + "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" + } + ] + }, + { + "seqno": 251, + "wire": "88c8c5c4588aa47e561cc5819704008b6496e4593e9403aa693f7504008940bb71905c684a62d1bf6c96c361be94138a6a225410022500cdc6c1700e298b46fff1", + "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" + } + ] + }, + { + "seqno": 252, + "wire": "88cbc8c7588ca47e561cc5802f3afb2e099f6496dd6d5f4a01f532db528200595001b826ae05953168df6c96c361be94138a436cca08010a8115c033700d298b46fff4", + "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" + } + ] + }, + { + "seqno": 253, + "wire": "88cecbca588aa47e561cc581a640d85c6496df3dbf4a01e5349fba820044a04571915c138a62d1bf6c96e4593e94134a6a225410022502cdc69cb8cbaa62d1bff7", + "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" + } + ] + }, + { + "seqno": 254, + "wire": "88d1cecd588ca47e561cc581913cf01c03bf6496df697e940bea693f750400b2a005704edc0baa62d1bf6c96d07abe94034a6a225410020500fdc6dcb8db6a62d1bffa", + "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" + } + ] + }, + { + "seqno": 255, + "wire": "88d4d1d0588ba47e561cc581965c744e356496e4593e940894be522820044a045702f5c0b4a62d1bff6c96c361be940baa436cca080112816ae05bb801298b46ff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 256, + "wire": "88d8d5d4588ba47e561cc58196da65e7dc6496c361be940b4a5f291410022502cdc10ae01c53168dff6c96d07abe940b2a436cca0801128115c03b702f298b46ffc1", + "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" + } + ] + }, + { + "seqno": 257, + "wire": "88dbe10f0d8313a26f6c96df3dbf4a002a693f7504008940b3704ddc0054c5a37fe0dfdbde52848fd24a8f", + "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" + } + ] + }, + { + "seqno": 258, + "wire": "886196dc34fd280654d27eea0801128115c6ddb807d4c5a37f5f911d75d0620d263d4c795ba0fb8d04b0d5a76c96c361be940094d27eea080112810dc6dab82794c5a37fc6e4e1e36496d07abe94032a5f2914100225022b8dbb700fa98b46ffe35a839bd9ab", + "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" + } + ] + }, + { + "seqno": 259, + "wire": "88c25f87352398ac5754df0f0d8369e133e1e7e6c0e5c4", + "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" + } + ] + }, + { + "seqno": 260, + "wire": "88e3e9c5c9e7e4e6e2e5bf0f0d03353938c4", + "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" + } + ] + }, + { + "seqno": 261, + "wire": "88e3be0f0d8369969a6c96c361be9403ea6e2d6a08010a8076e09fb820298b46ffe8e7e3e6c5", + "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" + } + ] + }, + { + "seqno": 262, + "wire": "88e4e1e0588aa47e561cc581f101c6436496e4593e940b4a693f75040089403571a0dc0054c5a37f6c96dc34fd281654d444a820044a01bb827ee09d53168dffcd", + "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" + } + ] + }, + { + "seqno": 263, + "wire": "88e7e4e3588ba47e561cc58020780103c06496c361be9403ca681d8a08016540b3702ddc0814c5a37f6c96d07abe9413aa612c6a0801128115c106e040a62d1bffd0", + "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" + } + ] + }, + { + "seqno": 264, + "wire": "88eae7e6588ca47e561cc5802fb2d3edb8f76496dc34fd2816d4cb6d4a0801654086e34fdc6de53168df6c96dc34fd28165486d99410021502ddc086e32d298b46ffd3", + "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" + } + ] + }, + { + "seqno": 265, + "wire": "88edeae9588ba47e561cc5804dbeeb60736496d07abe94032a5f291410022502d5c13d71b714c5a37f6c96df697e94034a6e2d6a080112807ee36cdc65d53168dfd6", + "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" + } + ] + }, + { + "seqno": 266, + "wire": "88f0edec588ca47e561cc5804e882f3ceb3f6496dc34fd281694dc5ad41002ca8166e34ddc032a62d1bf6c96dc34fd28112984b1a820042a0437041b82654c5a37ffd9", + "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" + } + ] + }, + { + "seqno": 267, + "wire": "88f3f0ef588ba47e561cc581965d75d75b6496e4593e940894be522820044a05bb8166e09b53168dff6c96c361be940baa436cca080112807ae09ab8cbea62d1bfdc", + "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" + } + ] + }, + { + "seqno": 268, + "wire": "88f6f3f2588ba47e561cc581a134e800f76496dc34fd2821297ca4504008940b971a05c65e53168dff6c96dc34fd282794cb6d0a080112806ee320b81694c5a37fdf", + "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" + } + ] + }, + { + "seqno": 269, + "wire": "88f9f6f5588ba47e561cc5802f05b6da676496dc34fd282694d27eea0801128166e05cb81654c5a37f6c96dc34fd282129b8b5a820044a045702fdc034a62d1bffe2", + "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" + } + ] + }, + { + "seqno": 270, + "wire": "886196dc34fd280654d27eea0801128115c6ddb810298b46fffaf9588aa47e561cc5804e81d0836496df697e94038a693f7504008940b9700fdc0014c5a37f6c96dd6d5f4a09e535112a0801128072e32cdc640a62d1bfe6", + "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" + } + ] + }, + { + "seqno": 271, + "wire": "88e0df6c96c361be940094d27eea080112807ae321b81694c5a37fe7408721eaa8a4498f5788ea52d6b0e83772ff7b8b84842d695b05443c86aa6f768586b19272ffe0e1588ba47e561cc5804dbe20001f", + "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" + } + ] + }, + { + "seqno": 272, + "wire": "88c6768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc5802ebe07c2df6496dc34fd282694d27eea0801128072e09bb8d36a62d1bf6c96dd6d5f4a09953716b5040089400ae001700053168dfff0", + "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" + } + ] + }, + { + "seqno": 273, + "wire": "88cbc2c1588aa47e561cc5802d082f7f6496dc34fd280654d27eea0801128172e36d5c03ca62d1bf6c96dc34fd280654d27eea080112806ee019b81694c5a37ff3", + "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" + } + ] + }, + { + "seqno": 274, + "wire": "88cec5c4588ba47e561cc5819744c842f76496dd6d5f4a05c52f948a080112816ee01fb80794c5a37f6c96df3dbf4a01f521b665040089403d71966e05953168dff6", + "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" + } + ] + }, + { + "seqno": 275, + "wire": "88d1c8c7588ba47e561cc581a7196db6596496df3dbf4a09d52f948a080112806ae32e5c032a62d1bf6c96df3dbf4a05f532db42820044a01bb8cbf704d298b46ff9", + "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" + } + ] + }, + { + "seqno": 276, + "wire": "88d4cbca588ca47e561cc580220b2f3a107f6496dd6d5f4a09a5340ec50400b2a00171a7ee000a62d1bf6c96c361be9413aa651d4a0801128166e059b8c814c5a37f798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 277, + "wire": "88d8cfce588ca47e561cc5802fb2e84427ff6496dc34fd2816d4cb6d4a08016540bb71b05c6df53168df6c96dc34fd28165486d99410021500cdc03f7190a98b46ffc1", + "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" + } + ] + }, + { + "seqno": 278, + "wire": "88dbd2d1588ba47e561cc58191004cb4ef6496d07abe940814be522820044a05ab827ee32ea98b46ff6c96df697e94105486d99410022500fdc6c5702da98b46ffc4", + "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" + } + ] + }, + { + "seqno": 279, + "wire": "88ded5d4588ba47e561cc581971d79a65d6496dd6d5f4a05c52f948a0801128015c69ab82754c5a37f6c96c361be94081486d99410022500fdc10ae32e298b46ffc7", + "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" + } + ] + }, + { + "seqno": 280, + "wire": "88e1d8d7588ba47e561cc5802079b6c4cf6496c361be940b8a693f75040089400ae09fb81654c5a37f6c96df697e9403ea6a225410022500fdc6d9b80694c5a37fca", + "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" + } + ] + }, + { + "seqno": 281, + "wire": "886196dc34fd280654d27eea0801128115c6ddb807d4c5a37f5f911d75d0620d263d4c795ba0fb8d04b0d5a7e2cce1e0df5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 282, + "wire": "88e7dedd588ba47e561cc581b0844268406496e4593e940bca65b6a50400b4a01bb8cbb7190298b46f6c96dc34fd28079486d9941000fa8066e32e5c640a62d1bfd0", + "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" + } + ] + }, + { + "seqno": 283, + "wire": "88c3c26c96c361be940094d27eea0801128166e32edc6c4a62d1bfd1e6e5e4c2", + "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" + } + ] + }, + { + "seqno": 284, + "wire": "88ebe2e1588ba47e561cc581a65e0bef356496d07abe94134a5f291410022500e5c082e05a53168dff6c96e4593e94136a65b685040089400ae321b800a98b46ffd4", + "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" + } + ] + }, + { + "seqno": 285, + "wire": "88eee5e4588ba47e561cc581d640d85b6f6496dd6d5f4a09d5328ea50400b2a005700fdc69b53168df6c96c361be940bca681fa50400894082e322b800298b46ffd7", + "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" + } + ] + }, + { + "seqno": 286, + "wire": "88f1e8e7588ca47e561cc5802cb2d000277f6496dc34fd28071486bb141002ca8215c64171b754c5a37f6c96c361be94640a5f291410021502edc69fb8cb8a62d1bfda", + "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" + } + ] + }, + { + "seqno": 287, + "wire": "88f4ebea588ba47e561cc58196c2ebef356496c361be940b4a5f291410022500e5c082e05a53168dff6c96df697e940b4a436cca0801128015c643700253168dffdd", + "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" + } + ] + }, + { + "seqno": 288, + "wire": "88f7eeed588ba47e561cc581a79d136d0b6496dc34fd2827d4be522820044a085704e5c0894c5a37ff6c96c361be940b2a65b68504008940bb71b7ee01b53168dfe0", + "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" + } + ] + }, + { + "seqno": 289, + "wire": "88d35f87352398ac5754df0f0d8469e7590f6c96c361be940094d27eea080112810dc03f702053168dfff7f56496d07abe94032a5f2914100225022b8dbb700fa98b46fff552848fd24a8f", + "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" + } + ] + }, + { + "seqno": 290, + "wire": "886196dc34fd280654d27eea0801128115c6ddb810298b46fff6f5588ba47e561cc5802f36dbee3b6496dd6d5f4a09b5349fba820044a001704fdc6dd53168df6c96c361be941054dc5ad410022502cdc6c3719714c5a37fe8", + "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" + } + ] + }, + { + "seqno": 291, + "wire": "88c1f9f8588ba47e561cc5802cb6e89c0f6496d07abe940bea693f75040089403771b7ae042a62d1bf6c96e4593e94032a6a2254100225002b8db7700f298b46ffeb", + "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" + } + ] + }, + { + "seqno": 292, + "wire": "88c4768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc5802213a100416496d07abe94136a681d8a08016540b37196ae000a62d1bf6c96df697e94134a651d4a080112810dc699b827d4c5a37ff0", + "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" + } + ] + }, + { + "seqno": 293, + "wire": "886196dc34fd280654d27eea0801128115c6ddb810a98b46ffc3c2588ba47e561cc5802071f6db6f6496df3dbf4a05b5349fba820044a085700cdc036a62d1bf6c96df697e9403ea6a225410022502f5c69bb820298b46fff4", + "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" + } + ] + }, + { + "seqno": 294, + "wire": "88c1c6c5588ba47e561cc5819085a0b2f76496dd6d5f4a01f52f948a0801128166e36fdc13ea62d1bf6c96df3dbf4a099521b6650400894082e362b8cb6a62d1bff7", + "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" + } + ] + }, + { + "seqno": 295, + "wire": "88c4c9c8588ca47e561cc5802d89b68210ff6496d07abe9413ea435d8a080165400ae045704253168dff6c96e4593e940b8a693f750400854082e09cb8d3ca62d1bffa", + "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" + } + ] + }, + { + "seqno": 296, + "wire": "88d35f87352398ac4c697f0f0d8371e65a6c96df3dbf4a002a693f7504008940b3704ddc0054c5a37f408721eaa8a4498f5788ea52d6b0e83772ff768586b19272ffd86496d07abe94032a5f2914100225022b8dbb702053168dff588ba47e561cc5804dbe20001f", + "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" + } + ] + }, + { + "seqno": 297, + "wire": "88cdd2d1588ba47e561cc5802fb6e09b676496d07abe94138a693f7504008940357041b82694c5a37f6c96e4593e940bea6e2d6a0801128072e01eb8d34a62d1bf798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 298, + "wire": "88d1d6d5588ba47e561cc58190b8d38fb96496d07abe940814be522820044a01ab8015c03aa62d1bff6c96e4593e94109486d99410022500e5c69db817d4c5a37fc1", + "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" + } + ] + }, + { + "seqno": 299, + "wire": "88d4d9d8588ca47e561cc5802db4e38f3e2f6496e4593e940054d03f4a08016540b3702f5c69953168df6c96c361be940854d27eea08010a8115c0b5700e298b46ffc4", + "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" + } + ] + }, + { + "seqno": 300, + "wire": "88d7dcdb588aa47e561cc581b700c8bf6496dd6d5f4a01a5349fba820044a01ab8c86e01953168df6c96c361be940094d27eea080112806ee34fdc138a62d1bfc7", + "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" + } + ] + }, + { + "seqno": 301, + "wire": "88dadfde588ba47e561cc581d704c85c7f6496e4593e94640a651d4a08016540bd71905c0014c5a37f6c96c361be940854d03f4a080112800dc6c37191298b46ffca", + "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" + } + ] + }, + { + "seqno": 302, + "wire": "88dde2e1588ca47e561cc580227c4d38e37f6496df697e94009486bb141002ca8066e01eb81714c5a37f6c96d07abe9403ea651d4a080112807ae32ddc0054c5a37fcd", + "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" + } + ] + }, + { + "seqno": 303, + "wire": "88e0e5e4588ba47e561cc5804175c0803f6496e4593e9413ca693f7504008940bb704ddc644a62d1bf6c96c361be940b4a6e2d6a080112806ae001704f298b46ffd0", + "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" + } + ] + }, + { + "seqno": 304, + "wire": "88e3e8e7588ca47e561cc5802d000e85d6bf6496dd6d5f4a05a521aec50400b2a05bb8d82e01b53168df6c96df3dbf4a05b52f948a08010a8076e043704ca98b46ffd3", + "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" + } + ] + }, + { + "seqno": 305, + "wire": "88e6ebea588ba47e561cc5802d32f3cdb76496df697e941014d27eea080112806ae32f5c038a62d1bf6c96d07abe940054d444a820044a01bb8cb7704153168dffd6", + "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" + } + ] + }, + { + "seqno": 306, + "wire": "88e9eeed588ba47e561cc581c644cb8dbd6496df697e940b6a651d4a08016540bb7190dc13ea62d1bf6c96dd6d5f4a040a65b6a5040089403371a7ae32d298b46fd9", + "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" + } + ] + }, + { + "seqno": 307, + "wire": "88ecf1f0588aa47e561cc581a0b810ff6496dd6d5f4a01a5349fba820044a00171905c684a62d1bf6c96c361be940094d27eea0801128166e360b80794c5a37fdc", + "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" + } + ] + }, + { + "seqno": 308, + "wire": "88eff4f3588ca47e561cc5804d81d105c6bf6496df697e94101486d9941002ca8176e09cb8cb6a62d1bf6c96dd6d5f4a019521aec5040085403371b7ae09953168dfdf", + "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" + } + ] + }, + { + "seqno": 309, + "wire": "88f2f7f6588ca47e561cc5802c800d32177f6496e4593e94032a435d8a0801654006e05bb8d3ca62d1bf6c96dc34fd280754ca3a94100225022b817ee36ea98b46ffe2", + "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" + } + ] + }, + { + "seqno": 310, + "wire": "88f5faf9588aa47e561cc581d75e005b6496d07abe940894d27eea0801128166e01ab80714c5a37f6c96df697e940b8a6a2254100225022b8d33704153168dffe5", + "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" + } + ] + }, + { + "seqno": 311, + "wire": "88f8768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc5802ebaf32cb56496dc34fd282694d27eea0801128015c6dcb806d4c5a37f6c96dd6d5f4a09953716b5040089403d71b7ee09953168dfea", + "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" + } + ] + }, + { + "seqno": 312, + "wire": "886196dc34fd280654d27eea0801128115c6ddb810a98b46ffc3c2588ba47e561cc581b6d90b626f6496dd6d5f4a01c5328ea50400b2a059b827ee05c53168df6c96df3dbf4a09e532db52820044a04371b66e000a62d1bfee", + "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" + } + ] + }, + { + "seqno": 313, + "wire": "88c1c6c5588ba47e561cc5804d38f38eb76496dd6d5f4a004a5f2914100225002b8d06e34e298b46ff6c96c361be9403aa6e2d6a080112807ee09eb800298b46fff1", + "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" + } + ] + }, + { + "seqno": 314, + "wire": "88c4c9c8588ba47e561cc58022132f36cf6496dc34fd281754d27eea0801128172e36d5c69a53168df6c96dc34fd280714d444a820044a01bb8015c034a62d1bfff4", + "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" + } + ] + }, + { + "seqno": 315, + "wire": "88c7cccb588ba47e561cc581969f704fb76496c361be940b4a5f2914100225000b807ae34e298b46ff6c96df697e940b4a436cca080112816ae32d5c0054c5a37ff7", + "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" + } + ] + }, + { + "seqno": 316, + "wire": "886196dc34fd280654d27eea0801128115c6ddb807d4c5a37f5f911d75d0620d263d4c795ba0fb8d04b0d5a76c96df3dbf4a002a693f7504008940b3704ddc0054c5a37ffa408721eaa8a4498f5788ea52d6b0e83772ff7b8b84842d695b05443c86aa6f768586b19272ff6496d07abe94032a5f2914100225022b8dbb700fa98b46ff588ba47e561cc5804dbe20001f5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 317, + "wire": "88d3d8d7588ca47e561cc580400b6003ce7f6496d07abe94134a65b6a50400b2a05eb810dc6dd53168df6c96df697e94138a65b685040085400ae09db8cbea62d1bf798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 318, + "wire": "88d7dcdb588ba47e561cc581b036ebefbf6496df697e940054ca3a941002ca800dc6ddb810298b46ff6c96d07abe9403ea65b6850400894082e36edc0b2a62d1bfc1", + "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" + } + ] + }, + { + "seqno": 319, + "wire": "886196dc34fd280654d27eea0801128115c6ddb811298b46ffe0df588ba47e561cc5804e059680df6496d07abe94032a5f291410022502f5c6d9b8dbaa62d1bf6c96df697e94034a6e2d6a080112800dc03371a0a98b46ffc5", + "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" + } + ] + }, + { + "seqno": 320, + "wire": "88c1e3e2588ba47e561cc581a65c6da6596496d07abe94134a5f2914100225001b8cb5704da98b46ff6c96e4593e94136a65b6850400894086e342b8d36a62d1bfc8", + "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" + } + ] + }, + { + "seqno": 321, + "wire": "88c4e6e5588ca47e561cc5802fbccb4d3c0f6496c361be941054cb6d4a080165400ae321b8d894c5a37f6c96df697e94009486d99410021500fdc69db8d894c5a37fcb", + "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" + } + ] + }, + { + "seqno": 322, + "wire": "88c7e9e8588aa47e561cc58021138f7f6496dc34fd280654d27eea0801128172e01bb800298b46ff6c96dc34fd280654d27eea0801128072e341b8cb6a62d1bfce", + "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" + } + ] + }, + { + "seqno": 323, + "wire": "88caeceb588ba47e561cc581b702e09c776496d07abe9403aa651d4a08016540b37001b8cbea62d1bf6c96df697e94138a65b6a5040089408ae34f5c0baa62d1bfd1", + "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" + } + ] + }, + { + "seqno": 324, + "wire": "88cdefee588ba47e561cc581d138cb6c8b6496dc34fd282714ca3a941002ca816ae32e5c034a62d1bf6c96dc34fd2817d4d03f4a080112807ee32fdc13aa62d1bfd4", + "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" + } + ] + }, + { + "seqno": 325, + "wire": "887688cbbb58980ae05c5f6196dc34fd280654d27eea0801128115c6ddb80794c5a37ff3df0f0d847da6da6b588ca47e561cc58190b6cb80003f0f1390fe420642175a001e7c2d38ebee85efe76496df697e94101486d9941002ca8166e341b817d4c5a37f6c96dd6d5f4a01e532db42820044a05ab8176e01f53168df", + "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" + } + ] + }, + { + "seqno": 326, + "wire": "88d55f87352398ac4c697f7f2488cc52d6b4341bb97f0f0d033732336c96df697e94134a65b685040089403371b7ee09953168df6496d07abe94032a5f2914100225022b8dbb702253168dffe252848fd24a8fe5dee640864d832148790b9365a13aeb4279a6c0d01b0b4fb4d8021032207fe30f28adf06416290bdcc42c00fb50be6b3585441badabe94032b693f758400b2a04571b76e01d53168dff6a5634cf031f", + "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=/" + } + ] + }, + { + "seqno": 327, + "wire": "88dbc30f0d8365d13de9e8e6c0e4bf", + "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" + } + ] + }, + { + "seqno": 328, + "wire": "88dbc30f0d03393837e9e8e6c0e4bf", + "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" + } + ] + }, + { + "seqno": 329, + "wire": "88dbc30f0d8364207be9e8e6c0e4bf", + "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" + } + ] + }, + { + "seqno": 330, + "wire": "88dbea6c96d07abe9413ea6a225410022500fdc03b71a0298b46ffe0e9e8e7c1e5e40f0d03353938c0", + "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" + } + ] + }, + { + "seqno": 331, + "wire": "88dceb0f0d033731376c96c361be940094d27eea0801128166e32edc6c4a62d1bfeae8c2e6c1", + "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" + } + ] + }, + { + "seqno": 332, + "wire": "88ddec6c96c361be940094d27eea080112810dc03f702053168dffe2ebeae9c3e7e60f0d03393733c2", + "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" + } + ] + }, + { + "seqno": 333, + "wire": "88de5f87352398ac5754df0f0d03333836bfeceac4e8c3", + "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" + } + ] + }, + { + "seqno": 334, + "wire": "88dfee6c96e4593e94136a65b685040089403b7000b8d34a62d1bfe4edecebe8c5e90f0d03353834c4", + "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" + } + ] + }, + { + "seqno": 335, + "wire": "88e05f86497ca582211f6c96e4593e94640a681fa50400894033702d5c65b53168dfe6efeeedc7ebea0f0d03343239c6", + "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" + } + ] + }, + { + "seqno": 336, + "wire": "88e2f10f0d8313a26f6c96c361be940094d27eea080112807ae321b81694c5a37ff0eec8ecc7e7efeb", + "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" + } + ] + }, + { + "seqno": 337, + "wire": "88e3cb0f0d0234336c96df3dbf4a05a535112a0801028105c082e34da98b46fff1efc86496d07abe94032a5f2914100225022b8dbb702053168dffee", + "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" + } + ] + }, + { + "seqno": 338, + "wire": "88e5c40f0d830b8cb3c5f2f0caeec9", + "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" + } + ] + }, + { + "seqno": 339, + "wire": "88e5cd0f0d03373333c0f2f0caeec9", + "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" + } + ] + }, + { + "seqno": 340, + "wire": "88e5c40f0d830b8d3b6c96c361be940094d27eea0801128105c69fb807d4c5a37ff3f1cbefca", + "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" + } + ] + }, + { + "seqno": 341, + "wire": "88e6768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc580220bae321f6496dc34fd281754d27eea080112816ee043700ca98b46ff6c96dc34fd280714d444a820044a01eb827ee32053168dffef", + "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" + } + ] + }, + { + "seqno": 342, + "wire": "88ebc2c1588ba47e561cc581a7d96d975f6496dd6d5f4a32052f948a080112816ee36cdc642a62d1bf6c96df3dbf4a044a65b685040089403b700d5c65953168dff2", + "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" + } + ] + }, + { + "seqno": 343, + "wire": "88eec5c4588aa47e561cc581f680f83f6496dd6d5f4a01a5349fba820044a05bb806ee084a62d1bf6c96df3dbf4a002a693f75040089403d71a05c6c4a62d1bff5", + "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" + } + ] + }, + { + "seqno": 344, + "wire": "88f1c8c7588aa47e561cc5804e3c20376496df697e94038a693f7504008940b7704edc0baa62d1bf6c96dd6d5f4a09e535112a0801128076e36edc0054c5a37ff8", + "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" + } + ] + }, + { + "seqno": 345, + "wire": "88f4cbca588ba47e561cc58196c0175f076496c361be940b4a5f2914100225001b8d02e084a62d1bff6c96df697e940b4a436cca080112810dc64171b1298b46fffb", + "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" + } + ] + }, + { + "seqno": 346, + "wire": "88f7cecd588ba47e561cc5802079f65c776496c361be940b8a693f75040089403371966e05f53168df6c96df697e9403ea6a225410022500edc69ab8dbaa62d1bf798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 347, + "wire": "88fbd2d1588ba47e561cc581b0badbe1776496e4593e940094ca3a941002ca8105c685704fa98b46ff6c96c361be94038a65b68504008940bb704e5c65e53168dfc1", + "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" + } + ] + }, + { + "seqno": 348, + "wire": "886196dc34fd280654d27eea0801128115c6ddb811298b46ffd6d5588ba47e561cc5804f09c7da776496df3dbf4a01c52f948a0801128072e04571b7d4c5a37f6c96df3dbf4a320521b665040089400ae09bb8cbca62d1bfc5", + "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" + } + ] + }, + { + "seqno": 349, + "wire": "88c15f911d75d0620d263d4c795ba0fb8d04b0d5a7e4c67f2b88ea52d6b0e83772ff7b8b84842d695b05443c86aa6f768586b19272ffeb588ba47e561cc5804dbe20001f5a839bd9ab0f0d03353630ec", + "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" + } + ] + }, + { + "seqno": 350, + "wire": "88c7e70f0d8313cd83e3c2c0edbfec", + "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" + } + ] + }, + { + "seqno": 351, + "wire": "88c7e70f0d83085f73e8c2c0edbfec", + "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" + } + ] + }, + { + "seqno": 352, + "wire": "88c7f00f0d830bc06be8c2c0edbfec", + "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" + } + ] + }, + { + "seqno": 353, + "wire": "88c7de0f0d830b22076c96e4593e94640a681fa50400894033702fdc0bca62d1bfc3c1eec0ed", + "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" + } + ] + }, + { + "seqno": 354, + "wire": "88c8dfbeccc3c2c1eec0bf0f0d830bef83ed", + "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" + } + ] + }, + { + "seqno": 355, + "wire": "88c8e0df588ca47e561cc5802d09c640eb9f6496e4593e940baa435d8a08016540b571b6ee01e53168df6c96c361be9403ea5f291410021500fdc006e080a62d1bffcf", + "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" + } + ] + }, + { + "seqno": 356, + "wire": "88cbe3e2588ba47e561cc5804079c65b0f6496df697e9413aa693f7504008940b9704fdc69953168df6c96dd6d5f4a05c53716b5040089403771b15c0814c5a37fd2", + "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" + } + ] + }, + { + "seqno": 357, + "wire": "88cee6e5588ba47e561cc581c65f13c0776496e4593e940b8a651d4a080165408ae34cdc6df53168df6c96c361be9403ca65b6a504008940b3704cdc65e53168dfd5", + "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" + } + ] + }, + { + "seqno": 358, + "wire": "88d1e9e8588ba47e561cc581a65d65b13d6496d07abe94134a5f291410022500cdc69fb820298b46ff6c96e4593e94136a65b685040089403b7022b8db8a62d1bfd8", + "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" + } + ] + }, + { + "seqno": 359, + "wire": "88d4eceb588aa47e561cc581f70006d96496e4593e940b4a693f7504008940b77197ae01b53168df6c96c361be940894d444a820044a01db8cb7704da98b46ffdb", + "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" + } + ] + }, + { + "seqno": 360, + "wire": "88d7efee588ba47e561cc5802d34e36db96496df697e941014d27eea0801128072e34e5c13ca62d1bf6c96d07abe940054d444a820044a003702f5c65f53168dffde", + "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" + } + ] + }, + { + "seqno": 361, + "wire": "88daf2f1588ca47e561cc5802cbac800f3ff6496df3dbf4a042a435d8a0801654082e362b800a98b46ff6c96e4593e941054be522820042a05db8076e32ca98b46ffe1", + "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" + } + ] + }, + { + "seqno": 362, + "wire": "88ddf5f4588ba47e561cc581a69a740f3f6496df697e94136a5f2914100225000b816ee082a62d1bff6c96d07abe94132a65b68504008940b57040b8db2a62d1bfe4", + "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" + } + ] + }, + { + "seqno": 363, + "wire": "88e0f8f7588ba47e561cc5802069e7d9076496df3dbf4a05b5349fba820044a05cb817ee084a62d1bf6c96e4593e940814d444a820044a01cb8115c6c2a62d1bffe7", + "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" + } + ] + }, + { + "seqno": 364, + "wire": "885f8b497ca58e83ee3412c3569f0f138afe5a005970200bef7f3f52848fd24a8f6c96e4593e941014cb6d4a0801128172e32fdc6dd53168dfe0dd0f0d830bc27be67686bbcb73015c1f", + "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" + } + ] + }, + { + "seqno": 365, + "wire": "88e7768b1d6324e5502b857138b83f5f88352398ac74acb37f588ca47e561cc5804cbae36db8f76496d07abe94036a436cca08016540b571905c0014c5a37f6c96df697e94032a681fa5040085403f71b0dc65b53168dff0", + "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" + } + ] + }, + { + "seqno": 366, + "wire": "88ecc17f2888cc52d6b4341bb97f0f0d837da71c6c96e4593e94136a65b685040089403971b7ae34ea98b46f6496d07abe94032a5f2914100225022b8dbb702253168dffe7c8e8f3e9e6", + "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" + } + ] + }, + { + "seqno": 367, + "wire": "88efc5c4588ba47e561cc5804eb2e09f0f6496e4593e94036a5f291410022500ddc00ae01953168dff6c96dc34fd2800a9b8b5a820044a01ab8d3b7190298b46fff6", + "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" + } + ] + }, + { + "seqno": 368, + "wire": "88f2c8c7588ba47e561cc581d1004d85df6496c361be94136a651d4a0801654106e32fdc03ea62d1bf6c96dd6d5f4a080a681fa504008940bf71966e05e53168dff9", + "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" + } + ] + }, + { + "seqno": 369, + "wire": "886196dc34fd280654d27eea0801128115c6ddb81654c5a37fcccb588aa47e561cc581f704f05c6496e4593e940b4a693f7504008940b9704d5c03ea62d1bf6c96c361be940894d444a820044a01cb8066e082a62d1bff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 370, + "wire": "88fad0cf588ca47e561cc5804f3cfbccb61f6496c361be94034a6a22541002ca8005c0b9704d298b46ff6c96df697e94034a651d4a08010a816ae05eb8d814c5a37fc1", + "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" + } + ] + }, + { + "seqno": 371, + "wire": "88c5d3d2588ca47e561cc5804e3e100997ff6496e4593e940854dc5ad41002ca8005c006e044a62d1bff6c96dc34fd2817d4c258d410021502d5c69fb81694c5a37fc4", + "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" + } + ] + }, + { + "seqno": 372, + "wire": "88c8d6d5588ba47e561cc58190b4d34fff6496e4593e9403aa693f750400894035702f5c0094c5a37f6c96dc34fd282754d444a820044a01cb816ee32d298b46ffc7", + "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" + } + ] + }, + { + "seqno": 373, + "wire": "88cbd9d8588ca47e561cc5802eb2065c781f6496e4593e941094d03f4a08016540bf7190dc6d953168df6c96df3dbf4a09f53716b5040085413371a76e36ca98b46fca", + "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" + } + ] + }, + { + "seqno": 374, + "wire": "88cedcdb588ba47e561cc581e75a1321736496df697e940894c258d41002ca8176e085704fa98b46ff6c96dd6d5f4a05b521aec50400894035700e5c682a62d1bfcd", + "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" + } + ] + }, + { + "seqno": 375, + "wire": "88d1dfde588aa47e561cc581f6c206836496e4593e940b4a693f7504008940b3700edc6da53168df6c96c361be940894d444a820044a0457196ee36053168dffd0", + "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" + } + ] + }, + { + "seqno": 376, + "wire": "88d4e2e1588ca47e561cc5802265b75f7dbf6496df697e94138a681d8a08016540b371a66e34f298b46f6c96dd6d5f4a084a651d4a080112810dc135700253168dffd3", + "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" + } + ] + }, + { + "seqno": 377, + "wire": "886196dc34fd280654d27eea0801128115c6ddb811298b46ff5f87352398ac5754dfe20f0d84640279ff6c96df697e94640a6a225410022500f5c0b57190298b46ffe1588ba47e561cc5804dbe20001fec768586b19272ffd87b8b84842d695b05443c86aa6f40864d832148790b9365a13aeb4279a6c0d01b0b4fb4d8021032207f5a839bd9ab0f28adf06416290bdcc42c00fb50be6b3585441badabe94032b693f758400b2a04571b76e01d53168dff6a5634cf031f", + "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=/" + } + ] + }, + { + "seqno": 378, + "wire": "88dfedec588ba47e561cc581c7c4d32db36496df697e941094ca3a941002ca8172e099b80714c5a37f6c96dd6d5f4a09d5340fd2820044a01cb806ee09d53168dfde", + "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" + } + ] + }, + { + "seqno": 379, + "wire": "88e2f0ef588ca47e561cc58196df7de65a7b6496e4593e94136a5f29141002ca806ae09fb8d054c5a37f6c96dc34fd282694cb6d0a080102806ee362b81714c5a37fe1", + "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" + } + ] + }, + { + "seqno": 380, + "wire": "88e5f3f2588aa47e561cc581a03217036497df3dbf4a01e5349fba820044a01ab8db9719694c5a37ff6c96df3dbf4a09b535112a080112806ae36f5c640a62d1bfe4", + "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" + } + ] + }, + { + "seqno": 381, + "wire": "88e8f6f5588ca47e561cc5802175f6df79df6496e4593e941014d03b141002ca800dc65db800298b46ff6c96dc34fd280694c258d4100225021b8cbb7197d4c5a37fe7", + "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" + } + ] + }, + { + "seqno": 382, + "wire": "88ebf9f8588ba47e561cc581a69c71c75e6496df697e94136a5f291410022500ddc68371b0a98b46ff6c96d07abe94132a65b6850400894033704edc6dd53168dfea", + "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" + } + ] + }, + { + "seqno": 383, + "wire": "88ee768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc581a65e03c26b6496d07abe94134a5f291410022500ddc6c171b754c5a37f6c96e4593e94136a65b6850400894033700fdc69b53168dfef", + "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" + } + ] + }, + { + "seqno": 384, + "wire": "88f3c2c1588ba47e561cc581a65d0002f76496d07abe94134a5f2914100225002b8d82e36153168dff6c96e4593e94136a65b685040089403f700fdc6dd53168dff2", + "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" + } + ] + }, + { + "seqno": 385, + "wire": "88f6c5c4588ca47e561cc58042034e38fb7f6496df697e940b8a65b6850400b2a05db8015c03ca62d1bf6c96dd6d5f4a044a65b6a5040085403571a76e084a62d1bff5", + "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" + } + ] + }, + { + "seqno": 386, + "wire": "885f8b497ca58e83ee3412c3569f0f138afe42ebedbecb6cbad7f352848fd24a8f6c96df3dbf4a080a6e2d6a0801128072e320b8c854c5a37fdddb0f0d033439306196dc34fd280654d27eea0801128115c6ddb81654c5a37f76841d6324e5", + "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" + } + ] + }, + { + "seqno": 387, + "wire": "88bfcdcc588ba47e561cc5802f059680ff6496dc34fd282694d27eea0801128115c68171a1298b46ff6c96dc34fd282129b8b5a820044a059b8c82e05a53168dff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 388, + "wire": "88c3d1d0588ba47e561cc5804cbc10b60f6496dc34fd2800a97ca45040089400ae099b80654c5a37ff6c96dd6d5f4a01f53716b50400894082e01bb8cb2a62d1bfc1", + "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" + } + ] + }, + { + "seqno": 389, + "wire": "88c6d4d3588ca47e561cc5802203cdb407bf6496dc34fd282654d03b141002ca8105c002e34153168dff6c96dc34fd282794ca3a9410022502f5c6c1702ea98b46ffc4", + "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" + } + ] + }, + { + "seqno": 390, + "wire": "88c9d7d6588ba47e561cc581d71c03226f6496df3dbf4a3215328ea50400b2a01ab8d3f702f298b46f6c96df3dbf4a040a681fa50400894037702cdc0094c5a37fc7", + "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" + } + ] + }, + { + "seqno": 391, + "wire": "88ccdad9588ca47e561cc580407990be067f6496df697e940094cb6d0a08016540b77196ee32e298b46f6c96dd6d5f4a040a65b685040085403b71a05c138a62d1bfca", + "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" + } + ] + }, + { + "seqno": 392, + "wire": "88f4dc0f0d8468427d9f6c96e4593e94640a681fa50400894033702fdc0bca62d1bf408721eaa8a4498f5788ea52d6b0e83772fff26496d07abe94032a5f2914100225022b8dbb702253168dfff4d4cdf2f0", + "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" + } + ] + }, + { + "seqno": 393, + "wire": "88d2e0df588ca47e561cc5802c884eb2d37f6496c361be94036a435d8a08016540b77022b8dbca62d1bf6c96d07abe940094ca3a9410022500f5c13771a654c5a37fd0", + "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" + } + ] + }, + { + "seqno": 394, + "wire": "88d5e3e2588ba47e561cc581b71b79b0376496df697e9403ca651d4a0801654002e34ddc65e53168df6c96d07abe94136a65b6a504008940b37040b82654c5a37fd3", + "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" + } + ] + }, + { + "seqno": 395, + "wire": "88d8e6e5588ba47e561cc5802cbeeb4ebb6496d07abe940bea693f7504008940bb700f5c640a62d1bf6c96df697e940094d444a820044a01ab8cb5719794c5a37fd6", + "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" + } + ] + }, + { + "seqno": 396, + "wire": "88dbe9e8588ba47e561cc5819081e1041f6496dd6d5f4a01f52f948a0801128115c102e34ca98b46ff6c96df3dbf4a099521b66504008940b57020b81654c5a37fd9", + "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" + } + ] + }, + { + "seqno": 397, + "wire": "88deeceb588ba47e561cc58020780f09af6496c361be940b8a693f750400894006e04171b754c5a37f6c96df697e9403ea6a2254100225022b827ee34da98b46ffdc", + "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" + } + ] + }, + { + "seqno": 398, + "wire": "88e1efee588ca47e561cc580206da69e703f6496df697e94036a681d8a08016540b5700d5c6da53168df6c96dd6d5f4a01a5340ec50400894082e341b8d814c5a37fdf", + "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" + } + ] + }, + { + "seqno": 399, + "wire": "88e4f2f1588ba47e561cc581f659702ebb6496df697e940bea612c6a08016540b57040b810298b46ff6c96dd6d5f4a002a435d8a0801128105c086e05e53168dffe2", + "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" + } + ] + }, + { + "seqno": 400, + "wire": "886196dc34fd280654d27eea0801128115c6ddb81694c5a37ff6f5588ba47e561cc581f69d038fff6496e4593e940b4a693f75040089408ae00371a654c5a37f6c96c361be940894d444a820044a05ab8d3d702da98b46ffe6", + "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" + } + ] + }, + { + "seqno": 401, + "wire": "88c1f9f8588ba47e561cc5802d3acbc0676496df697e941014d27eea080112816ae081719754c5a37f6c96dd6d5f4a32053716b50400894082e041704f298b46ffe9", + "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" + } + ] + }, + { + "seqno": 402, + "wire": "88c4768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc5802cbedb6e0b6496d07abe940bea693f7504008940b971972e32e298b46f6c96df697e940094d444a820044a01bb8cbd704fa98b46ffee", + "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" + } + ] + }, + { + "seqno": 403, + "wire": "88f3c2c1588ba47e561cc581a03c20b4ff6496df3dbf4a080a5f291410022502f5c6d9b801298b46ff6c96e4593e94005486d994100225001b806ee32da98b46fff1", + "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" + } + ] + }, + { + "seqno": 404, + "wire": "88ccc5c4588ba47e561cc581a0080113ff6496df3dbf4a080a5f2914100225001b8cbf704ca98b46ff6c96df3dbf4a004a436cca080112810dc64571b6d4c5a37ff4", + "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" + } + ] + }, + { + "seqno": 405, + "wire": "88cfc8c7588ca47e561cc5819036cb22107f6496df697e941094d444a8200595042b826ae05b53168dff6c96dc34fd282754d27eea080102817ae019b811298b46fff7", + "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" + } + ] + }, + { + "seqno": 406, + "wire": "88d2cbca588ba47e561cc581f136079e736496d07abe940bca612c6a08016540b57197ae34053168df6c96df697e94032a435d8a080112807ee32d5c1054c5a37ffa", + "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" + } + ] + }, + { + "seqno": 407, + "wire": "88d5cecd588ba47e561cc581d75f702db36496c361be940054c258d41002ca817ae32cdc03aa62d1bf6c96d07abe9403aa681fa50400894006e34ddc13ca62d1bf798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 408, + "wire": "88d9d2d1588ca47e561cc58022680cb4f3bf6496e4593e9413aa681d8a080165400ae085700153168dff6c96dc34fd2820a994752820044a041700edc680a62d1bffc1", + "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" + } + ] + }, + { + "seqno": 409, + "wire": "88dcd5d4588aa47e561cc5819684d05c6496e4593e9403aa693f75040089408ae01ab810298b46ff6c96c361be94138a6a225410022502d5c699b821298b46ffc4", + "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" + } + ] + }, + { + "seqno": 410, + "wire": "88dfd8d7588ca47e561cc5802c81a69f703f6496e4593e94032a435d8a080165408ae32cdc0b6a62d1bf6c96c361be94038a651d4a0801128166e34ddc0894c5a37fc7", + "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" + } + ] + }, + { + "seqno": 411, + "wire": "88e2dbda588aa47e561cc581f036f3ff6496dd6d5f4a01a5349fba820044a05ab8076e01953168df6c96df3dbf4a002a693f750400894082e32edc65b53168dfca", + "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" + } + ] + }, + { + "seqno": 412, + "wire": "88e5dedd588ca47e561cc5802c844f36cb9f6496df3dbf4a01a521aec50400b2a04371a72e040a62d1bf6c96e4593e94034a651d4a080112816ee05fb821298b46ffcd", + "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" + } + ] + }, + { + "seqno": 413, + "wire": "88e8e1e0588ba47e561cc58196db744cbd6496c361be940b4a5f291410022502edc0357191298b46ff6c96d07abe940b2a436cca080112806ae342b8cbaa62d1bfd0", + "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" + } + ] + }, + { + "seqno": 414, + "wire": "88ebe4e3588ba47e561cc5804cb4f32cbf6496c361be94640a693f7504008940bb702e5c0b2a62d1bf6c96d07abe940814dc5ad410022500d5c0bf702da98b46ffd3", + "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" + } + ] + }, + { + "seqno": 415, + "wire": "88eee7e6588aa47e561cc5819032071b6496e4593e9403aa693f750400894006e01eb817d4c5a37f6c96dc34fd282754d444a820044a0457196ee01a53168dffd6", + "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" + } + ] + }, + { + "seqno": 416, + "wire": "88f1eae9588ba47e561cc5819742c85c7f6496dd6d5f4a05c52f948a0801128115c133704ca98b46ff6c96df3dbf4a01f521b66504008940b5700d5c6db53168dfd9", + "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" + } + ] + }, + { + "seqno": 417, + "wire": "88f4edec588ba47e561cc58196db71c6456496c361be940b4a5f291410022502e5c6dab82714c5a37f6c96d07abe940b2a436cca080112806ee00571b0298b46ffdc", + "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" + } + ] + }, + { + "seqno": 418, + "wire": "88f7f0ef588ba47e561cc581a75f64400f6496dc34fd2827d4be522820044a001704cdc6db53168dff6c96dd6d5f4a05b532db42820044a05ab8066e36253168dfdf", + "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" + } + ] + }, + { + "seqno": 419, + "wire": "88faf3f2588ba47e561cc581a79e03afff6496c361be9403ea693f7504008940357190dc6d953168df6c96df697e94132a6a225410022500ddc69db8db6a62d1bfe2", + "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" + } + ] + }, + { + "seqno": 420, + "wire": "886196dc34fd280654d27eea0801128115c6ddb81694c5a37ff7f6588ca47e561cc580227df784f35f6496df697e94009486bb141002ca8266e32ddc0bca62d1bf6c96dc34fd280754ca3a9410022502ddc683700da98b46ffe6", + "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" + } + ] + }, + { + "seqno": 421, + "wire": "88c1faf9588ca47e561cc5819782fb4279af6496dd6d5f4a05f5328ea50400b4a05ab827ae32f298b46f6c96df3dbf4a019532db52820040a01fb8db5704e298b46fe9", + "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" + } + ] + }, + { + "seqno": 422, + "wire": "886196dc34fd280654d27eea0801128115c6ddb81654c5a37f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d840badbad76c96c361be94138a6a225410022500cdc002e000a62d1bff408721eaa8a4498f5788ea52d6b0e83772ff5a839bd9ab768586b19272ff6496dc34fd280654d27eea0801128166e36edc0b2a62d1bf5889a47e561cc58197000f", + "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" + } + ] + }, + { + "seqno": 423, + "wire": "88cc768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc58020081a69ef6496df3dbf4a05b5349fba820044a01bb8cbd700253168df6c96df3dbf4a042a6a225410022500cdc65bb8cbaa62d1bff6", + "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" + } + ] + }, + { + "seqno": 424, + "wire": "88d1c2c1588ba47e561cc581b75971f07f6496dc34fd281029a4fdd410022500d5c0bd71a694c5a37f6c96dd6d5f4a082a6a225410022500e5c0b5702ca98b46fff9", + "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" + } + ] + }, + { + "seqno": 425, + "wire": "88d4c5c4588ba47e561cc581f71f036db96496dc34fd282654c258d41002ca8172e34e5c640a62d1bf6c96dc34fd282694d03b1410022500ddc0bd71a0a98b46ff798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 426, + "wire": "88d8c9c8588ca47e561cc58040744e81b73f6496d07abe940054cb6d0a0801654082e09eb810298b46ff6c96df697e940894cb6d0a08010a8176e36ddc1094c5a37fc1", + "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" + } + ] + }, + { + "seqno": 427, + "wire": "88dbcccb588ba47e561cc581b79c740eb96496df3dbf4a040a651d4a0801654082e341b8d814c5a37f6c96e4593e941014cb6d4a0801128176e09eb800a98b46ffc4", + "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" + } + ] + }, + { + "seqno": 428, + "wire": "88decfce588ba47e561cc5802fb2f3c16f6496dd6d5f4a09b5349fba820044a099b8c82e34fa98b46f6c96e4593e940bea6e2d6a080112816ee360b80694c5a37fc7", + "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" + } + ] + }, + { + "seqno": 429, + "wire": "88e1d2d1588ca47e561cc5804db41740cbff6496dc34fd28269486d9941002ca8176e05ab8cb2a62d1bf6c96dc34fd282714d03b1410021500d5c10ae32da98b46ffca", + "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" + } + ] + }, + { + "seqno": 430, + "wire": "886196dc34fd280654d27eea0801128115c6ddb816d4c5a37fd6d5588ba47e561cc580226de101af6496dd6d5f4a05e5349fba820044a005704edc0bea62d1bf6c96c361be94036a6a225410022500fdc6ddb80714c5a37fce", + "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" + } + ] + }, + { + "seqno": 431, + "wire": "88c1d9d8588ba47e561cc5802f36db8f356496dd6d5f4a09b5349fba820044a001704ddc0bea62d1bf6c96c361be941054dc5ad410022502d5c006e01c53168dffd1", + "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" + } + ] + }, + { + "seqno": 432, + "wire": "88c4dcdb588ba47e561cc581c69e7dc6df6496df3dbf4a05d5328ea50400b2a05bb8cbd702d298b46f6c96e4593e94038a65b6a5040089403b7196ee05d53168dfd4", + "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" + } + ] + }, + { + "seqno": 433, + "wire": "88c7dfde588ba47e561cc581a7dd13a06f6496d07abe94642a5f2914100225002b816ee34053168dff6c96e4593e940854cb6d0a0801128105c102e09b53168dffd7", + "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" + } + ] + }, + { + "seqno": 434, + "wire": "88cae2e1588ba47e561cc581a03adbeebf6496df3dbf4a080a5f291410022502edc082e05a53168dff6c96e4593e94005486d99410022500d5c643702e298b46ffda", + "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" + } + ] + }, + { + "seqno": 435, + "wire": "88cd7686bbcb73015c1f0f0d0231365f90497ca589d34d1f649c7620a98268faff5885aec3771a4b0f28bbbb7f6dee3876ffef6ec8f0614ead7b9c4fff20a63f3572087a3f7e5a677715bfbb5ea7bf6e3f6a5634cf031f6a487a466aa0b2b5e319a4b5721e9f7f2e88cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 436, + "wire": "88d1c10f0d023136c0bf0f28babb7f6dee3876ffedd6a784c01a1fd44ffe414c7e6ae410f47efcb4ceee2b7f76bd4f7edc7ed4ac699e063ed490f48cd541656bc633496ae43d3fbe", + "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" + } + ] + }, + { + "seqno": 437, + "wire": "88d1c10f0d023136c0bf0f28bbbb7f6dee3876ffef269a3b457a5676dea7ff90531f9ab9043d1fbf2d33bb8adfddaf53dfb71fb52b1a67818fb5243d233550595af18cd25ab90f4fbe", + "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" + } + ] + }, + { + "seqno": 438, + "wire": "88d1c10f0d023136c0bf0f28bbbb7f6dee3876ffefc76fcc9a1b6e747ae7ffc8298fcd5c821e8fdf9699ddc56feed7a9efdb8fda958d33c0c7da921e919aa82cad78c6692d5c87a7be", + "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" + } + ] + }, + { + "seqno": 439, + "wire": "88d15f87497ca589d34d1f0f0d840badbad76c92dc34a9a4fdd45195040b8dbb702da820045ff0efee6496d07abe94138a65b68502fbeea806ee001700053168df5892ace84ac49ca4eb003e94aec2ac49ca4eb003e24085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 440, + "wire": "88d6eeed588aa47e561cc581a6590b826496df3dbf4a01e5349fba820044a059b8172e32ea98b46f6c96e4593e94134a6a2254100225022b817ae32053168dffe6", + "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" + } + ] + }, + { + "seqno": 441, + "wire": "88d9f1f0588aa47e561cc581d005a7836496dd6d5f4a042a693f7504008940b771a7ae32e298b46f6c96df3dbf4a05e535112a0801128076e05ab8cb2a62d1bfe9", + "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" + } + ] + }, + { + "seqno": 442, + "wire": "88dcf4f3588ba47e561cc581a75965c73f6496c361be9403ea693f750400894002e09cb8d054c5a37f6c96df697e94132a6a225410022502cdc6deb82654c5a37fec", + "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" + } + ] + }, + { + "seqno": 443, + "wire": "88dff7f6588ba47e561cc581b6c4c81d7b6496dd6d5f4a01c5328ea50400b2a043700f5c65953168df6c97df3dbf4a09e532db52820044a05cb8cb57197d4c5a37ffef", + "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" + } + ] + }, + { + "seqno": 444, + "wire": "88e2faf9588ca47e561cc5802e3adbe213ff6496df3dbf4a05c5340fd28200595022b8176e34d298b46f6c96e4593e940894d444a820042a05ab8172e05d53168dfff2", + "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" + } + ] + }, + { + "seqno": 445, + "wire": "88e5768b1d6324e5502b857138b83f5f88352398ac74acb37f588ba47e561cc581a0bcfb4fbf6496dc34fd2821297ca450400894002e342b81694c5a37ff6c96dd6d5f4a09f532db42820044a059b8276e05d53168dff7", + "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" + } + ] + }, + { + "seqno": 446, + "wire": "887688cbbb58980ae05c5feb5f8b497ca58e83ee3412c3569ff97f1a842507417f0f138afe44e01d65d0b4ebbfcf6c96df697e940bca6e2d6a080112806ee34fdc0baa62d1bf6496dd6d5f4a05d5340ec50400b2a01cb8272e05c53168df588ca47e561cc5802db6d880007f7b8b84842d695b05443c86aa6f5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 447, + "wire": "88c5f2c4798624f6d5d4b27fc40f138afe440719109c109dfe7f6c96c361be940094d27eea0801128105c65fb82714c5a37f6496dc34fd280654d27eea0801128166e01fb8cbca62d1bf5889a47e561cc5802f001fc3c2", + "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" + } + ] + }, + { + "seqno": 448, + "wire": "88f6cecd588ba47e561cc5802cb4dbcf076496d07abe940bea693f75040089400ae34f5c65c53168df6c96e4593e94032a6a225410022500fdc0b5719654c5a37fc4", + "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" + } + ] + }, + { + "seqno": 449, + "wire": "88f9d1d0588aa47e561cc581f700e33f6496dd6d5f4a01a5349fba820044a05bb8cbd702f298b46f6c96df3dbf4a002a693f75040089403b7196ee01e53168dfc7", + "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" + } + ] + }, + { + "seqno": 450, + "wire": "88fcd4d3588ba47e561cc5819702ebae396496dc34fd2816d4be522820044a01fb8db3704153168dff6c96dc34fd2810a90db32820044a05fb806ee01953168dffca", + "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" + } + ] + }, + { + "seqno": 451, + "wire": "886196dc34fd280654d27eea0801128115c6ddb816d4c5a37fd8d7588ca47e561cc5802169f71b781f6496dc34fd281714d03b141002ca816ae09cb8db6a62d1bf6c96dc34fd2810a984b1a820044a01fb8dbb71b6d4c5a37fce", + "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" + } + ] + }, + { + "seqno": 452, + "wire": "88c1dbda588aa47e561cc581903a17db6496e4593e9403aa693f75040089400ae05db810298b46ff6c96dc34fd282754d444a820044a041702edc134a62d1bffd1", + "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" + } + ] + }, + { + "seqno": 453, + "wire": "88d9c45f86497ca582211fd2d80f1389fe5c0bc17c4f32f7f36c96df3dbf4a002a693f75040089408ae34fdc6d953168dfd5d4", + "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" + } + ] + }, + { + "seqno": 454, + "wire": "88db6196dc34fd280654d27eea0801128115c6ddb81714c5a37f5f87352398ac5754dfdb0f0d837dd7df0f138afe44ebacb2e85e033fcf52848fd24a8f6c96df697e94640a6a225410022500cdc6deb811298b46ff6496c361be9403ea693f75040089403f71b6ae36e298b46f588aa47e561cc581c034f001", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_23.json b/http/http-client/src/test/resources/hpack-test-case/story_23.json new file mode 100644 index 0000000000..9b69873532 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_23.json @@ -0,0 +1,14132 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264016196dc34fd280654d27eea0801128166e32edc0814c5a37f769086b19272b025c4b884a7f5c2a379feff0f28ff3dbb76f2dc325f81b6dd034fc6d842d15c04ae34f8d96df036d05975b1899744eb5215b2040204a1085e13829196d92b426a56dc6c1a0fecd45035452b6a88a05440544f68190d524e89d56635440c9524b42a2068191510356e5440fc54400815115e5598d5102ceeab230b8a88a0544faa2062293a9d514a2004000802a88184d61653f9545285c544507da85f359ac2a20dd6d5f4a0195b49fbac16540b371976e040a62d1bfed4ac699e063ed490f48cd540bc7191721d7b7afdff0f1f909d29aee30c78f1e178e322e43af6f5630f0d82109f408721eaa8a4498f57842507417f5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88768586b19272ff588eaec3771a4bf4a523f2b0e62c0e035f87497ca589d34d1f5a839bd9ab6496dc34fd280654d27eea0801128166e32edc65e53168df0f13b1fe64948e3f201970430b617996d98e49247a51824211d24ab34f92594aecaf05d246eb6d48c89a0bafb4400d92bef87f9f4088f2b563a169ce84ff93ac7401a757278f099578e322e43af6f5b8f03f0f0d84136179cf6196dc34fd280654d27eea0801128166e32edc0854c5a37f7f0788ea52d6b0e83772ff408af2b10649cab0c8931eaf90d70eedca7f551ea588324e51c7417fbf4088f2b10649cab0e62f0233337b05582d43444e", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "886196dc34fd280654d27eea0801128166e32edc0894c5a37fc96c96d07abe940b6a6a2254100225020b8d0ae36ea98b46ff52848fd24a8f5888a47e561cc581f0036496dc34fd280654d27eea0801128166e362b810a98b46ff7b8b84842d695b05443c86aa6fcb0f0d8313416b5501304088ea52d6b0e83772ff8d49a929ed4c0d7d2948fcc0175b7f0a88cc52d6b4341bb97f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88d2588aa47e561cc581e71a003f5f89352398ac7958c43d5fd16496dd6d5f4a01a5349fba820044a059b8cbb702253168df0f13b1fe64948e3f201970430b617996d98e49247a51824211d24ab34f92594aecaf05d246eb6d48c89a0bafb4400d92bef87f9fd00f0d03393538cac2cdcccb6c96e4593e9413ca65b6a5040038a05ab8c8ae34ca98b46fc9c57f058d49a929ed4c0d7d2948fcc017c1", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88d7c76c96df3dbf4a01b5340fd2820042a01fb816ee36fa98b46fcbd50f0d8369d79cc4588ca47e561cc581903cd36fba0f6496dc34fd282714d444a820059502cdc6dcb8d094c5a37fcfd3", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88769086b19272b025c4b85f53fae151bcff7f0f138ffe6408d66872ba58da92479e781fcf6496df697e940b2a693f750400894086e362b806d4c5a37f588ba47e561cc5804dbe20001fcd6c96d07abe940baa6a225410021502cdc65db821298b46ffd1db0f0d830884ef5f901d75d0620d263d4c741f71a0961ab4ff6196dc34fd280654d27eea0801128166e32edc0b2a62d1bfd9", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88c30f138ffe5c75d59a1cae9636a3940d001fcf6496df697e940b2a693f750400894086e34fdc6c2a62d1bfc2d16c96d07abe940baa6a225410021502cdc65db820298b46ffd5df0f0d033634345f86497ca582211fc1dc", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88c66c96d07abe9413ea6a225410022502cdc64371b6d4c5a37f0f138ffe5923eb34491914617191bc407f3fd7588ca47e561cc58190b6cb80003f6496df3dbf4a321535112a080165403d71a76e36253168dfd6e30f0d03343138c5c4df", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88c9c00f138ffe44175668923228c2e3237880fe7fd9bf6496df3dbf4a321535112a080165403d71a7ae01953168dfd7e40f0d821043c6c5e0", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88ca6c96df3dbf4a042a6a2254100225020b807ae09e53168dff0f138ffe5d642e2cd123236400dc925003f9dbc16496df3dbf4a09a535112a080165403d7040b8d894c5a37fd9e60f0d836de6dbc4c7e2", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88cc6c96d07abe9413ea6a225410022502cdc659b80654c5a37f0f138ffe5d0b4459a248c8a36dd0b41203f9ddc36496df3dbf4a321535112a080165403d71a7ae01d53168dfdbe80f0d836de7c3c6c9e4", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88ce6c96e4593e940b8a693f7504008540b771a15c0b8a62d1bf0f138ffe5b2904b3518648e5111e138007f3dfc56496df697e940baa6e2d6a0801654086e34ddc65b53168dfddea0f0d83759799cccbe6", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88d06c96df3dbf4a042a6a2254100225020b807ae09c53168dff0f1390fe5a0c8facd123236403cf363781fcffe1c76496df3dbf4a09a535112a080165403d7041b810a98b46ffdfeccecd0f0d836dd133e8", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88d26c96d07abe9413ea6a225410022502cdc645700153168dff0f1390fe5f009f59a248c8a30c72b2e340fe7fe3c9c8e0ed0f0d84085f71dfcfcee9", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "88f0e06c96d07abe94138a435d8a080102816ae08571b7d4c5a37fe4ee0f0d03393136dd588ca47e561cc5804eb4179f0bbf6496d07abe940b8a6e2d6a0801654106e36fdc0814c5a37fd1ec", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88d66c96e4593e94038a65b68504008540bb702d5c036a62d1bf0f1390fe4401808b34375c7e31b32ca1681fcfe7cd6496df697e940baa6e2d6a0801654086e360b80654c5a37fe5f20f0d8465d79f17d46196dc34fd280654d27eea0801128166e32edc0b4a62d1bfef", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "88f6e66c96d07abe94138a435d8a080102816ae05eb8cb6a62d1bfeaf40f0d84642c81efe3588ca47e561cc5804eb4179e7d9f6496d07abe940b8a6e2d6a0801654106e36f5c69d53168dfc1f2", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "884003703370d6acf4189eac2cb07f33a535dc618f1e3c2f31cf35051c882d9dcc42a1721e962b1cc51c8c56cd6bf9a68fe7e94bdae0fe74eac8a5fc1c54d7ba1535eebea64e30a9938df5356fd6a6ae1b54d5bf6a9934df5356fbdfcf5f96497ca58e83ee3412c3569fb50938ec4153070df8567b0f138f0b80642179965f65d6db6df081a7ff6196dc34fd280654d27eea0801128115c69bb8db4a62d1bf6496dc34fd280654d27eea0801128166e34ddc6da53168df4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb59871a52324f496a4f5a839bd9ab768320e52f0f0d840842d37f408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5583640f35588faed8e8313e94a47e561cc58197000f", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88e76c96d07abe9413ea6a225410022502cdc64371b714c5a37f0f138ffe5d1086b344919146174458c00fe7f8de6496df3dbf4a321535112a080165403d71a7ae01c53168dff6c40f0d836de0b3e56196dc34fd280654d27eea0801128166e32edc0bca62d1bf7f3588ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "887689bf7b3e65a193777b3ff50f0d826402c7c0", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88bef50f0d826402c76196dc34fd280654d27eea0801128166e32edc0bea62d1bf", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "885f87352398ac4c697f6c96df697e9403ca681fa50400894102e01cb81794c5a37f6196c361be940094d27eea080112816ae320b810298b46ff6496dc34fd280654d27eea080112816ae320b810298b46ffce768344b2970f0d023433cb5584799109ff5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88768c86b19272ad78fe8e92b015c36c96dc34fd280654d27eea0801128166e32edc0bea62d1bf5890a47e561cc581e71a003e94aec3771a4b6496dd6d5f4a01a5349fba820044a059b8cbb702fa98b46f7f1ae9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f4088f2b5761c8b48348f89ae46568e61a002581f5f9e1d75d0620d263d4c741f71a0961ab4fd9271d882a60c9bb52cf3cdbeb07f798624f6d5d4b27fd77b8b84842d695b05443c86aa6fd1", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88769086b19272b025c4b85f53fae151bcff7f6c96e4593e94032a6a225410022502d5c102e042a62d1bff0f138ffe432c71acd12313cdb820b64203f952848fd24a8f588ba47e561cc5804dbe20001f6496c361be94640a693f7504008940b771a15c69b53168dfc3dd0f0d83644db55f901d75d0620d263d4c741f71a0961ab4ffd7d6", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88c36c96df3dbf4a042a6a2254100225020b807ae09a53168dff0f138ffe59948b3448c8d900e3f238007f3fc2fa6496df3dbf4a09a535112a080165403d7041b80654c5a37fc6e00f0d8308040f5f87352398ac5754dfdad9", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88c6c00f138efe6322cd1232364038fc8e001fcfc4588ca47e561cc58190b6cb80003f6496df3dbf4a09a535112a080165403d7040b8dbea62d1bfc9e30f0d03313838c0dcdb", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88c86c96df3dbf4a09d53716b50400894082e05bb8d854c5a37f0f138ffe44fb2b34418c8cbed3ad32407f3fc7c06496df3dbf4a019535112a080165403f71b0dc69c53168dfcbe5dade0f0d03363539dd", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88ca0f138ffe4212acd1063232fb4eb4c901fcff6496df3dbf4a019535112a080165403f71b0dc69b53168dfc2ccc0c9e60f0d03323836dbdfde", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88cb0f138ffe44dc8b34418c8cbed3ad32407f3f6496df3dbf4a019535112a080165403f71b0dc6dc53168dfc3cdc1cae70f0d03363035dce0df", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88cc6c96e4593e94642a6a225410022502edc0bf7191298b46ff0f1390fe4220cad2cd1246ca18c2ec61003f9fcb588ca47e561cc58190b4e81969ff6496df3dbf4a321535112a08016540bb702fdc644a62d1bfd0ea0f0d84081d6c1f5f86497ca582211fe4e3", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88e25f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d83132ebdece2", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "885f88352398ac74acb37f6c96c361be94134a65b6a50400854082e05ab8cbea62d1bf6196c361be940094d27eea0801128215c6deb8db2a62d1bf6496dc34fd280654d27eea0801128215c6deb8db2a62d1bff2e10f0d840880cb5fee55846c4e81dfe0", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "88e8c30f0d03333038f16196dc34fd280654d27eea0801128166e32edc1014c5a37f", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "88e9c40f0d03333038f2be", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "48826402bf768586b19272ff6495dc34fd2800a994752820000a0017000b800298b46f4085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf7f22caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f28bf40606c0fb61c0103ad5f68026dbfb50be6b3585441be7b7e940096d27eeb08017540b371976e080a62d1bfed4ac699e063ed490f48cd540bc7191721d7b7af0f1fffa3019d29aee30c206bc7191721d7b7ab11c646238c8c23fca8749609cf4957ac7317e2a44548a0f4547c54889054a0c9293ac0d81f6c3802075abed004db7f1314f1164324c7aa03549f8ac744561ed496090b28eda13f14d11543a4b0463b282a3b5a5f81d75c49f55960f058fe281d535a398b016a5b15df8a688bb96c418f54005c2d2e2f8ac7445e0b18ebae0f1e273d25ac7317e238c9152482a3a624153f0825852d5158541e8b5263d5005971cf2eb8f7c47476891032bb7f11d1da2b206576fe23a3b45de090b28eda12b783d9449e0d217e2a44512600b2d85f69f7997de71bf8a911120e1bf0acf7c548892682eddbca880b2a20633d25ac7317e2a445d1158e62db65104e94d6ab30b0c78f1e178e322e43af6f563e2a44561652d9616c830f0d033635367f31842507417f5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88dfd00f138ffe5c03d2acd1246ca18c2ec61003f9dd588ca47e561cc58190b4e819685fcfe1fb0f0d83702d83dbc7f3", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88e0da0f138ffe442656689191b201c7e47000fe7fded76496df3dbf4a09a535112a080165403d7040b8dbaa62d1bfe2fc0f0d03353437d9f5f4", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "88f3ce0f0d03333038fcc8", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "88e1db0f138ffe5e7e559a24646c8071f91c003f9fdfd86496df3dbf4a09a535112a080165403d7040b8d854c5a37fe3fd0f0d831080efdac9f5", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88c9c7c6c5c4c30f0d023433c2f2", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88f4cf0f0d03333038fdc9", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88e26c96d07abe9413ea6a225410022502cdc645700f298b46ff0f1390fe421904159a248c8a3108607000fe7fe1da6496df3dbf4a321535112a080165403d71a7ae040a62d1bfe55a839bd9ab0f0d84134279afe0f9f8", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "88f7d20f0d83644f87becc", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "885f8b497ca58e83ee3412c3569f6c96e4593e940bea6e2d6a080112817ae09bb8d3ea62d1bf6196c361be940094d27eea0801128205c0b5702153168dff6496dc34fd280654d27eea0801128205c0b5702153168dff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbf60f0d830b6f07408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5584704dbcfff6edc5", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "88ec6c96e4593e94642a6a225410022502edc0bf704e298b46ff0f138ffe431bb2acd1246ca11c64132f03f9eb588ca47e561cc58190b4e819683f6496df3dbf4a321535112a08016540bb702fdc138a62d1bff0c80f0d83740cbfe7d67f1088ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "88f0c10f138ffe4401b2b34491b28471904cbc0fe7ee588ca47e561cc58190b4e8196dcfc0f2ca0f0d837996dbddd8bf", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "887689bf7b3e65a193777b3fdf0f0d03333038cbd9", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88f2c30f138ffe59032f2cd1246ca11c64132f03f9f0588ca47e561cc58190b4e81965bfc2f4ccebda0f0d84089969afc1", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "88f4cccb6c96c361be9403aa6e2d6a0801128172e34e5c684a62d1bf6196dc34fd280654d27eea0801128105c13b700e298b46ff6496dd6d5f4a01a5349fba820044a041704edc038a62d1bfca768344b2970f0d84132f859fca5584085a0b5f5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "88f9ca0f138ffe432ca059a248d94238c8265e07f3f7c6c8fad20f0d83782eb9f1e0c7", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "88c5e60f0d03333038d26196dc34fd280654d27eea0801128166e32edc1054c5a37f", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "88fa588ca47e561cc581c640e880007fe76496d07abe94032a693f750400b4a01cb8db5700d298b46f54012a6c96dc34fd280654d27eea0801128072e360b8d32a62d1bf0f0d8365e083e5cc", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "88fec1ea6496c361be94642a6a22541002d2820dc6dcb800298b46ffc06c96e4593e94642a6a2254100225041b8d86e36fa98b46ff0f0d836c0d3fe7ce", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "88769086b19272b025c4b85f53fae151bcff7fc4ed6496d07abe94032a693f750400b4a01fb8d3b702ca98b46fc36c96dc34fd280654d27eea080112807ee321b82694c5a37f0f0d836c0e87ead1", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "887b8b84842d695b05443c86aa6fddf06c96df3dbf4a05f532db42820044a08571a7ee34ea98b46f6196c361be940094d27eea0801128215c03371b6d4c5a37f6496dc34fd280654d27eea0801128215c03371b6d4c5a37fdbce0f0d84642fb2e7da55846dc001cfcd", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "887f2afdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff3cdec6496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25f5f87352398ac4c697fe0768320e52f0f0d023432e0", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88cade0f138ffe59132b34491b28471904cbc0fe7f52848fd24a8f588ca47e561cc58190b4e8196c1fdec9e80f0d033830335f87352398ac5754dff7de", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88dcfd0f0d03333437e9d4", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88cd6c96e4593e94038a65b68504008540bb702d5c0054c5a37f0f1390fe4236dc2acd0dd71f8c60115e681fcfc1588ca47e561cc58190b6cb80003f6496df697e940baa6e2d6a0801654086e360b82794c5a37fcdec0f0d84640e342f5f901d75d0620d263d4c741f71a0961ab4fffbe2", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88ceedc66c96df697e94640a6a225410022502d5c13b704fa98b46ff6196c361be940094d27eea0801128205c13f702e298b46ff6496dc34fd280654d27eea0801128205c13f702e298b46ffebde0f0d840bc071bfea5584702e3cdfdd", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "880f28e1b1288a1861860d19edbaf39b11f9d711aff0f0e6787c3992bc3bb6d1a7878bbbdaa30d78368387e73c5838ffb675b5f6a5f3d2335502f617ba0865ea2a7ed4c1e6b3585441badabe94032b693f758400b2a059b8cbb704153168dff6a6b1a678184088f2b5761c8b48348f89ae46568e61a00f2c1f7f0fe9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f76035253495886a8eb10649cbf4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7798624f6d5d4b27ff9da6196dc34fd280654d27eea0801128166e32edc1014c5a37f", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88dee45f88352398ac74acb37f6496d07abe94032a693f750400b4a045700cdc65a53168dfe46c96dc34fd280654d27eea080112810dc00ae01f53168dff0f0d840b2eb4e7c1f2", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88e1f50f138ffe42cb8b34491b28471904cbc0fe7fd4588ca47e561cc58190b4e804fb5ff4df5a839bd9abd4ea0f0d826420f4", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88e3e9c26496d07abe94032a693f750400b4a01eb8076e09a53168dfe86c96dc34fd280654d27eea080112807ae01ab80654c5a37f0f0d84081d007fc5f6", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88768586b19272ffecc56496dd6d5f4a004a693f750400b4a04371a72e32053168dfeb6c96c361be940094d27eea080112810dc65db82654c5a37f0f0d8369975beff9", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88e8eec76496dd6d5f4a004a693f750400b4a019b816ae09c53168dfed6c96c361be940094d27eea0801128066e041700da98b46ff0f0d8365f71bf1fb", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88eaf0c96496dd6d5f4a004a693f750400b4a04571a7ee36ca98b46fef6c96c361be940094d27eea0801128115c65fb82654c5a37f0f0d8369e69af3408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88ed6c96c361be940094d27eea0801128166e099b810298b46ffe1588ca47e561cc58190b4f81e7dff6496dc34fd280129a4fdd41002ca8166e09eb8c814c5a37f0f0d840bcfb4ffcfd0c1", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88f06c96c361be940094d27eea0801128176e003702fa98b46ffe4e06496dd6d5f4a0195349fba8200595002b8005c0854c5a37f0f0d84136079bfd1d2c3", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88ca6c96c361be940094d27eea080112810dc641704da98b46ffe6d2588ca47e561cc58190b4fb2d099f6496dc34fd280129a4fdd41002ca816ae04171b794c5a37f0f0d8413afb2f7d5c6", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "88f5588ca47e561cc581c640e880007fd56496dd6d5f4a004a693f750400b4a01bb8d3f702ea98b46f54012a6c96c361be940094d27eea0801128015c699b8d38a62d1bf0f0d836db71f6196dc34fd280654d27eea0801128166e32edc1054c5a37fcb", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "488264026196dc34fd280654d27eea0801128166e32edc1094c5a37f768dd54d464db6154bf79812e05c1fc30f28da445dcd07feef6effe770ffc13cd42f6103e06c2e02fbd75670000003086f00207af5f6bff77b07ff3ed4c1e6b3585441be7b7e94504a693f750400baa059b8cbb704253168dff6a5f3d233550206bc7191721e9fb5358d33c0c70f1fff87049d29aee30c206bc7191721e962361086238c9e26a0f18e8aec3c8c058c6b884b8584004e3cf01c6c0fb8eb3fe43b2ec01f8ac84b204d9697e3b9a4aa013cd42f6103e06c2e02fbd75670000003086f00207af5f6be3e2a927803f09819545842054584400895101f5598597556611055101c54401340f8ef4a606b0bf0bacbf7be3bd32c11c645c2112e23babd454fc10b070df8567be09257033f158e62e91d258238c8a880abb79510273d25ac7317e268274a6b55985516154587c78f0bc7191721d7b7aaa2c3f04241c375ff824f04e7a4b58e62fc17b96a4a202f72d4917c4e18238c8abb7a73d25ac7317e3b8a0beab37eb1cc5d23a4bf046e0c9a6fe0fcf8eedc17d566f91bf823904e7a4b58e62fc77720beab37c8e7c102181034db6483f4abb782ab30b20ae9f8205b815161f8ee16e0beab37c816fe0817608e322a202aede54409cf496b1cc5f8ee1760beab37c8177e08c860c7bf467f8eec860beab37c8c87e08c8a0d274aa200fb8cd40e3a0bf1dd91417d566f91917c7769f82f9ac2912a8819ce393e08db3078f1e178e322e43af6f5f8eedb305f559be46d9f8236d413a535aacc2a8b0aa2c3e3c785e38c8b90ebdbd7e3bb6d417d566f91b6be08db7047191721e9f8eedb705f559be46dbf8236e417d566fd6398ba47497e3bb6e417d566f91b73e08dbb07a2a3e3bb6ec17d566f91b77e08e0a0f15d6abb7a892355dbd481e55dbd48a855dbd4b8655dbd486555dbd4d76aaedea44faaedea5a4aaedea5e07c7770505f559be4705f08802cb8e7975c7be09009af8e9005777e3bc1cfe3ac1cfe23f103efb5f11cf038d3ff15c1947dc6a8810d75d054aa206ba2d996354ab37765a6275de6a4aa881ae8b6658d52a203abbab85566efc43b30401f4003782d6386a50b34bb4bbf6496c361be940094d27eea0801128166e32edc1094c5a37f6c96dd6d5f4a01a5349fba820044a059b8cbb704253168df58a6a8eb10649cbf4a54759093d85fa5291f9587316007d2951d64d83a9129eca7e94aec3771a4bfe57f29bbacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee854d5c36a9934df52f6ad0a69878a9bb7c3fcff4086f282d9dcb67f85f1e3c3816b0f0d01304088ea52d6b0e83772ff8749a929ed4c016f7f1688cc52d6b4341bb97f5f87497ca58ae819aa", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "88769086b19272b025c4b85f53fae151bcff7f588aa47e561cc581e71a003fe76496dd6d5f4a01a5349fba820044a01fb8015c6dc53168dfcf6c96c361be940094d27eea080112807ee34e5c69f53168df0f0d83101a0fcedb0f1390fe48f086b34491e00198e395a681fcff52848fd24a8f", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "88c2c1ea6497dd6d5f4a01a5349fba820044a01fb8cb5719694c5a37ffd26c96c361be940094d27eea080112810dc659b80754c5a37f0f0d836c2eb3d1de0f1390fe5920db6d668923c17652b4f0880fe7c0", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88cfced30f28da445dcd07feef6effe770ffc13cd42f6103e06c2e02fbd75670000003086f00207af5f6bff77b07ff3ed4c1e6b3585441be7b7e94504a693f750400baa059b8cbb704253168dff6a5f3d233550206bc7191721e9fb5358d33c0c70f1fff87049d29aee30c206bc7191721e962361086238c9e26a0f18e8aec3c8c058c6b884b8584004e3cf01c6c0fb8eb3fe43b2ec01f8ac84b204d9697e3b9a4aa013cd42f6103e06c2e02fbd75670000003086f00207af5f6be3e2a927803f09819545842054584400895101f5598597556611055101c54401340f8ef4a606b0bf0bacbf7be3bd32c11c645c2112e23babd454fc10b070df8567be09257033f158e62e91d258238c8a880abb79510273d25ac7317e268274a6b55985516154587c78f0bc7191721d7b7aaa2c3f04241c375ff824f04e7a4b58e62fc17b96a4a202f72d4917c4e18238c8abb7a73d25ac7317e3b8a0beab37eb1cc5d23a4bf046e0c9a6fe0fcf8eedc17d566f91bf823904e7a4b58e62fc77720beab37c8e7c102181034db6483f4abb782ab30b20ae9f8205b815161f8ee16e0beab37c816fe0817608e322a202aede54409cf496b1cc5f8ee1760beab37c8177e08c860c7bf467f8eec860beab37c8c87e08c8a0d274aa200fb8cd40e3a0bf1dd91417d566f91917c7769f82f9ac2912a8819ce393e08db3078f1e178e322e43af6f5f8eedb305f559be46d9f8236d413a535aacc2a8b0aa2c3e3c785e38c8b90ebdbd7e3bb6d417d566f91b6be08db7047191721e9f8eedb705f559be46dbf8236e417d566fd6398ba47497e3bb6e417d566f91b73e08dbb07a2a3e3bb6ec17d566f91b77e08e0a0f15d6abb7a892355dbd481e55dbd48a855dbd4b8655dbd486555dbd4d76aaedea44faaedea5a4aaedea5e07c7770505f559be4705f08802cb8e7975c7be09009af8e9005777e3bc1cfe3ac1cfe23f103efb5f11cf038d3ff15c1947dc6a8810d75d054aa206ba2d996354ab37765a6275de6a4aa881ae8b6658d52a203abbab85566efc43b30401fcdcccbcaf1c97f0985f1e3c382070f0d023433c8c75f87352398ac4c697f0f1393fe5b03ed870044b3785e6566d96c0dde05dfe77b012a", + "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": "*" + } + ] + }, + { + "seqno": 75, + "wire": "88c76c96c361be940094d27eea0801128105c1357197d4c5a37fc4588ca47e561cc58190b4f01969ff6496dc34fd280129a4fdd41002ca8105c64571a0298b46ff0f0d8465a7dc67f2f3e4", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "88ca6c96df697e94132a6a225410022502fdc6c371a714c5a37fc7ca6496dd6d5f4a01a5349fba820044a019b8d8ae09d53168df0f0d840b8cb2dff4d9e60f1390fe5a704ecab3442472b4420dd79e07f3", + "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\"" + } + ] + }, + { + "seqno": 77, + "wire": "885f911d75d0620d263d4c795ba0fb8d04b0d5a77b8b84842d695b05443c86aa6ff26496dc34fd281754d27eea0801128166e32edc1054c5a37fdc0f0d83085a07e9589caec3771a4bf4a54759360ea44a7b29fa5291f958731600880fb8007f", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "88da6c96d07abe9403ea65b68504008940b97000b820298b46ff0f138ffe4216c4d01665e5a36e508a4003f9cd0f0d023536588ba47e561cc581d75d7000076496dd6d5f4a01d535112a0801128176e32ddc69a53168df7f0d85f1e3c34e375f901d75d0620d263d4c741f71a0961ab4ffe0ef", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88f66c96c361be940094d27eea0801128166e09bb8d054c5a37fd25f88352398ac74acb37f588ca47e561cc58190b6cb6fb4f76497dd6d5f4a0195349fba8200595001b8dbf71a654c5a37ff0f0d8468216ddf6196dc34fd280654d27eea0801128166e32edc1014c5a37ff4", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "88da6c96c361be940894d444a820044a05bb8d3f700fa98b46ffd7588ca47e561cc58190b6cb6ebee76496c361be940054d27eea0801654035700f5c6c4a62d1bf0f0d8469969f6fc4c1f7", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88ddeec46496d07abe94032a693f750400b4a043704fdc69a53168dfed6c96dc34fd280654d27eea080112810dc0b7704d298b46ff0f0d8479969b73c3f9", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88df6c96df3dbf4a002a693f7504008940b371b76e32ea98b46fdcdf6496dd6d5f4a01a5349fba820044a043702cdc6c0a62d1bf0f0d840bcc89afc8eefb0f1390fe5e204122cd12472571c905238d03f9", + "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\"" + } + ] + }, + { + "seqno": 83, + "wire": "89d2d15a839bd9ab6496d07abe940054ca3a940bef814002e001700053168dffee0f0d01307f2688ea52d6b0e83772ff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88e66c96df697e94640a6a225410022502ddc69ab8d36a62d1bfe3cee66496dc34fd280654d27eea080112817ae32fdc136a62d1bf0f0d8413410bdff3c20f1390fe631942facd12469e18da75f6da07f3", + "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\"" + } + ] + }, + { + "seqno": 85, + "wire": "8876a686b19272b025c4b884a7f5c2a379fed4a4f2448450c09712e2129aab2d5bb767600bbebbb27fe8d06496dd6d5f4a01a5349fba820044a01eb800dc6c0a62d1bff96c96c361be94138a6a2254100225041b826ee09b53168dff0f0d84105f7dfff6c50f1390fe5e24a37d668849492b6cc71c6d03f9e7", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88ebead26496dd6d5f4a01a5349fba820044a003704edc65c53168dffb6c96c361be940894d444a820044a05fb8c8ae34253168dff0f0d8413e0033ff8c70f1390fe6365f79959a24650900dbed0de07f3e9", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "88edecd46496dd6d5f4a01a5349fba820044a041702d5c1094c5a37f54012a6c96df3dbf4a002a693f7504008940b371b72e36253168df0f0d8413ceb42f6196dc34fd280654d27eea0801128166e32edc1054c5a37fcb0f1390fe5f8dd20166892392b8d09a642007f3ed", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88f1588ca47e561cc58190b4dba06dafd96496dc34fd280129a4fdd41002ca8115c03571a754c5a37fc26c96c361be940094d27eea080112810dc6ddb8cbca62d1bf0f0d84134d89cf6196dc34fd280654d27eea0801128166e32edc1094c5a37fcf0f1390fe5920db6d668923c17652b4f0880fe7f1", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "88f5f4dc6496dc34fd280654d27eea0801128176e09ab8db4a62d1bfc56c96c361be940094d27eea080112816ae340b8d014c5a37f0f0d8469b038d7c4d10f1390fe6524adb4b34491e68257e518c00fe7f3", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88e86c96d07abe9413ea6a225410022500cdc0bb719694c5a37f768821e8a0a4498f53df4003703370a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7fd65890aed8e8313e94a47e561cc581c034f0016196dc34fd280654d27eea0801128166e32edc132a62d1bf0f0d836da6c1d6ec", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "886196dc34fd280654d27eea0801128166e32edc134a62d1bf5f8b497ca58e83ee3412c3569f0f0d03313733d80f28eaef03cd3ccbc1189c7881132f04a291f7c31bd1ca391b03ed84a169b7a465f71671c65a03ccbed81f6c250b4f32d44cb2e39f6a17cd66b0a88370d3f4a0195b49fbac20044a05ab8076e09a53168dff6a5634cf031f6a487a466aa05cb2ca5224ddcb49468b6c2af5153f5886a8eb10649cbf640130768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbfdbc7", + "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\"" + } + ] + }, + { + "seqno": 92, + "wire": "88768586b19272fff46c96df697e940894cb6d0a08010a8172e00571b7d4c5a37f52848fd24a8fe20f0d03393238f7588ca47e561cc5804eb4179e7dff6496d07abe940b8a6e2d6a0801654106e36fdc038a62d1bf6196dc34fd280654d27eea0801128166e32edc13aa62d1bfe3", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "88c3f95f86497ca582211fe66c96df697e94640a6a225410022500f5c13971a754c5a37f588ca47e561cc581c13a075d71bf6496df3dbf4a320535112a080169403d704e5c6da53168df6196dc34fd280654d27eea0801128166e32edc13ea62d1bf0f0d8365a0bbe8", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88c87b8b84842d695b05443c86aa6fc3eb6c96df697e94640a6a225410022500f5c13b702e298b46ff0f0d8313417f588ca47e561cc581c13a075d6c3f6496df3dbf4a320535112a080169403d704e5c680a62d1bfc2ec", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "88ccc1c6eec00f0d83089e0f588ca47e561cc581c13a075d799f6496df3dbf4a320535112a080169403d704edc0894c5a37fc4ee", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88cec3c8f06c96df697e94640a6a225410022500f5c13b704f298b46ff588ca47e561cc581c13a075e0b3f6496df3dbf4a320535112a080169403d704edc684a62d1bfc70f0d023536f1", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88c7d16c96e4593e940bca693f7504003ea045702edc0094c5a37f0f0d83089d6f588aa47e561cc581969b70006496e4593e9403aa693f7504008940b371976e09f53168df7b05582d43444eea4088ea52d6b0e83772ff8e49a929ed4c0dfd2948fcc0ebaf7f7f3788cc52d6b4341bb97f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88d86c96c361be940894d444a820044a01fb8cb7700fa98b46ffc3eed30f0d03393431cff9408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692ff4089f2b511ad51c8324e5f834d9697c6", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "88dd6c96df697e941094d27eea08010a807ee360b8c894c5a37f4084f2b563938d1f739a4523b0fe105b148ed9bfd45a839bd9ab0f0d830b407fc6588ca47e561cc581965e0b2e81ff6496c361be9413ea693f750400b2a085702fdc0bca62d1bfd87f0a88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88e36c96df697e941094d27eea08010a807ee32fdc6da53168dfc3d9c20f0d8365a65cca588ca47e561cc581965e0b4cbad76496c361be9413ea693f750400b2a08571905c132a62d1bfdcc1", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88e66c96df697e941094d27eea08010a807ee321b82714c5a37fcdc6dcc50f0d03333438588ca47e561cc5819640eb8d36df6496df3dbf4a082a693f750400b2a01fb8c86e34d298b46fdfc4", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "88e9decfc8c76c96df3dbf4a044a65b6850400894086e09cb821298b46ff0f0d8365c71d588ca47e561cc581b65969d682cf6496d07abe940b4a65b6850400b4a0017041b801298b46ffe2c7", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "88ece1d2cbca6c96df3dbf4a044a65b6850400894086e09cb82754c5a37f0f0d830befbf588ca47e561cc581b644169b683f6496dc34fd28112996da141002d2810dc1397190298b46ffe5ca", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "48826401f05f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f0f1fc39d29aee30c169ad78e3219721d7b7ab05a6b62c2d051a0a8623b69ad8b0bdcc831ea430f81b13ef305a632c8bf447f85a6b83c1eca24f0690bf05a871d05bd414764010f0d033330355888a47e561cc580410f6496dc34fd280654d27eea0801128166e341b800298b46ffe9cee8", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "88f3e8edd16c96df697e94640a6a225410022500f5c13b704153168dff588ca47e561cc581c13a075d7dcf6496df3dbf4a320535112a080169403d704edc136a62d1bfec0f0d03333033d1", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "88f6ebf0d46c96df697e94640a6a225410022500f5c13b719754c5a37f0f0d8369d681588ca47e561cc581c13a075e10bf6496df3dbf4a320535112a080169403d704edc6c2a62d1bfefd4", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "88f96496dc34fd280654d27eea0801128166e32edc13aa62d1bf54012a5f87497ca589d34d1f0f0d847c220b9ff7d7e0dfdedde5", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88fc6c96df697e9403ea6a225410022502edc0b5700fa98b46ffe7c0e30f0d03343436f3d8e1e0dfdee6", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88fd6c96e4593e9413ca65b6850400814086e01db8cb8a62d1bff3dc0f0d8379a645e4588ca47e561cc581965e0b2eba1f6496c361be9413ea693f750400b2a0857040b820298b46fff6db", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88768586b19272ff6c96d07abe9403ea65b68504008940b7700fdc132a62d1bfe1f7e00f0d8310996bfc588ca47e561cc581b65969a038f76496dd6d5f4a059532db4282005a504cdc137702ea98b46ffadf", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "88c16c96df697e94132a6a225410022500edc65eb8cbca62d1bfe4fae30f0d830b8dbb5f87352398ac4c697f588ca47e561cc581c104000b2f7f6496df3dbf4a099535112a080169403b7197ee34ea98b46f6196dc34fd280654d27eea0801128166e32edc13ea62d1bfe4", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "88c67b8b84842d695b05443c86aa6f5f88352398ac74acb37feae96c96dc34fd280654d27eea0801128015c699b8cb2a62d1bf0f0d836da7dc588ca47e561cc581c640cb206dff6496d07abe94032a693f750400b4a00571a7ae09e53168dfc3e9", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88cbc2c6edec6c96dc34fd280654d27eea080112810dc00ae01f53168dff0f0d8369f7da588ca47e561cc581c640e09d643f6496d07abe94032a693f750400b4a043700cdc0014c5a37fc6ec", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88c6ce0f28e3bb8b864bf038d940fbedb62090a00bef91c13d205f6650b6f34ec71cb1c606590899723787189b75f2bf246c8caf36fbecca0fb50be6b3585441c8b27d28012da4fdd60b8a059b8cbb704fa98b46ffb52b1a67818fb5243d23355047191721d7b7afdf6c96e4593e940054d03b141000e2816ee059b8db8a62d1bf52848fd24a8f0f0d0234335896a47e561cc5801f4a547588324e5837152b5e39fa98bf6496dc34fd280654d27eea0801128166e32edc13ea62d1bf4088ea52d6b0e83772ff8e49a929ed4c0107d2948fcc01785f7f3288cc52d6b4341bb97fcf", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "88d45f911d75d0620d263d4c795ba0fb8d04b0d5a70f1fc39d29aee30c169ad78e3219721d7b7ab05a6b62c2d051a0a8623b69ad8b0bdcc831ea430f81b13ef305a632c8bf447f85a6b83c1eca24f0690bf05a871d05bd414764010f0d8313827b5888a47e561cc5802e396496dc34fd280654d27eea0801128166e340b816d4c5a37fcff5ce6c96e4593e940854cb6d0a0801128266e059b8c854c5a37fc6f9", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "88d8cfcef96c96dc34fd280654d27eea0801128005c106e01953168dff588ca47e561cc581c6402699685f6496d07abe94032a693f750400b4a001704cdc0854c5a37fd30f0d8365c135f9", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "88dbd2d1fc6c96dc34fd280654d27eea0801128005c106e09e53168dff0f0d8369c699588ca47e561cc581c6402699103f6496d07abe94032a693f750400b4a0017042b8d3ea62d1bfd67f0988ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88dfd65f86497ca582211f5a839bd9ab6c96df697e94640a6a225410022500fdc10ae36d298b46ff0f0d837c4eb7588ca47e561cc581c13a1081e7bf6496df3dbf4a320535112a080169403f7042b81754c5a37fdcc3", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "88e4dbcdc16c96df697e94640a6a225410022500fdc10ae36da98b46ff588ca47e561cc581c13a108597bf6496df3dbf4a320535112a080169403f704cdc03aa62d1bfdf0f0d84085f785fc6", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "88e7dd6c96dc34fd280654d27eea080112810dc13f71b694c5a37f0f0d836d9719588ca47e561cc581c640e34d005f6496d07abe94032a693f750400b4a04371905c6c4a62d1bf6196dc34fd280654d27eea0801128166e32edc640a62d1bfca", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "88769086b19272b025c4b85f53fae151bcff7f6c96df3dbf4a042a6a2254100225020b807ae09a53168dff0f138ffe5996559a24646c8071f91c003f9fdb588ca47e561cc58190b6cb80003f6496df3dbf4a09a535112a080165403d7042b82714c5a37fe6cc0f0d830804cf5f87352398ac5754dfc3cf", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "88f06c96dc34fd280654d27eea0801128005c65ab8db6a62d1bf4084f2b563938d1f739a4523b0fe105b148ed9bfe9cf0f0d836dc659e8588ca47e561cc581c64026c407ff6496d07abe94032a693f750400b4a00171976e32fa98b46fc7d3", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "88f46c96e4593e9403aa681d8a0801128105c699b8d3aa62d1bfebc1ecd20f0d83744e3f588ca47e561cc581a644cb6e099f6496df697e940bca681d8a08016941337190dc0894c5a37fefd6", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "88f7eed5d46c96df697e94640a6a225410022500f5c102e36d298b46ff588ca47e561cc581c13a075b135f6496df3dbf4a320535112a080169403d7042b8db2a62d1bff20f0d8465a65f6fd9", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "88fa6c96df697e94640a6a225410022500fdc10ae36ea98b46fff2d80f0d8413420bbfe4d36496df3dbf4a320535112a080169403f704cdc03ca62d1bfcfdb", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "88fcf3f2c8d96c96e4593e94642a6a225410022502ddc69eb82754c5a37f0f0d8410190b9f588ca47e561cc581c640d85e79ef6496d07abe94032a693f750400b4a01eb8015c0bca62d1bfd2de", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "88768586b19272fff76c96df697e940894cb6d0a08010a816ee36fdc03ea62d1bfefde0f0d84642c841fea588ca47e561cc5804eb4179e69df6496d07abe940b8a6e2d6a0801654106e36f5c0baa62d1bfd6e2", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "88c1fa6c96df697e940894cb6d0a08010a816ee36fdc0814c5a37ff2e10f0d84642e81efed588ca47e561cc5804eb4179d7dff6496d07abe940b8a6e2d6a0801654106e36edc642a62d1bf6196dc34fd280654d27eea0801128166e32edc644a62d1bfe6", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "88c57b8b84842d695b05443c86aa6ff1e56c96df3dbf4a044a65b6850400894082e005702fa98b46ff588ca47e561cc581b65969d13e1f6496d07abe940b4a65b6850400b4a001702fdc036a62d1bf6196dc34fd280654d27eea0801128166e32edc65a53168df0f0d03333538ebd8", + "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" + } + ] + }, + { + "seqno": 130, + "wire": "88cac2c9fae90f0d836dd7daea588ca47e561cc5804eb4179e6c1f6496d07abe940b8a6e2d6a0801654106e36f5c134a62d1bfc0ed", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "88ccc4f7eb6c96df3dbf4a044a65b6850400894082e005704053168dff588ca47e561cc581b6597da65b736496d07abe940b4a65b6850400b4a059b8266e32153168df6196dc34fd280654d27eea0801128166e32edc65b53168df0f0d8365d6dff1de", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88e46c96df3dbf4a09c521aec504008940b7704cdc0bea62d1bf0f1390fe5a6d98d66a32bee3e16a41ba407f3f52848fd24a8fe46496df697e940baa6e2d6a0801654086e362b80754c5a37fcbf20f0d8365a0335f901d75d0620d263d4c741f71a0961ab4ffc2f5", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "88d4cc5f911d75d0620d263d4c795ba0fb8d04b0d5a7f46c96df3dbf4a044a65b6850400894082e005704d298b46ff588ca47e561cc581b65a79d75c6f6496df697e940b6a65b6850400b4a05bb8205c1014c5a37fc60f0d83719785f9e6", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "88d8f3d0f70f0d830b206bc1588ca47e561cc581c13a1085917f6496df3dbf4a320535112a080169403f704cdc03ea62d1bf6196dc34fd280654d27eea0801128166e32edc65d53168df408721eaa8a4498f5788ea52d6b0e83772ffea", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "88bfdc0f139afe597c523451c636a492324aec71b407996c5195a71b205ffe7f5891a47e561cc5802e89e0001f4a5761bb8d254089f2b511ad51c8324e5f834d96975f8b497ca58e83ee3412c3569f0f0d033238364088ea52d6b0e83772ff8749a929ed4c0d377f0388cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 136, + "wire": "88e1d9ca5a839bd9ab6c96df697e94640a6a225410022500fdc10ae36d298b46ff588ca47e561cc581c13a1081f7ff6496df3dbf4a320535112a080169403f7042b8cb8a62d1bfc80f0d836dd79ec7f3", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "887689bf7b3e65a193777b3fcf0f0d83134107c26196dc34fd280654d27eea0801128166e32edc65e53168df", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "88bee76495dc34fd2800a994752820000a0017000b800298b46f4085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf4003703370caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f0d0234337f09842507417f5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 139, + "wire": "88e5c95f88352398ac74acb37f6c96df3dbf4a05f521aec504008940b97196ae05f53168df6196c361be940094d27eea0801128266e01cb8db6a62d1bf6496dc34fd280654d27eea0801128266e01cb8db6a62d1bf4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d837de65c408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f55846c42699f5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "88d9f60f139afe597c523451c636a492324aec71b407996c5195a71b205ffe7f588eaec3771a4bf4a523f2b0e62c0c83d7d60f0d023437d5d4", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "88cfe00f0d03333237d3ce", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "88f76c96d07abe9403ea65b68504008940b7700fdc1094c5a37ff0d40f0d03393730c9588ca47e561cc581b13ee3ce3edf6496e4593e9403ea65b6850400b4a05bb807ee05953168dfd1dc4084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "88fbf35f87352398ac5754dfbfd86c96d07abe9403ea65b68504008940b7700fdc1054c5a37f0f0d82089c588ca47e561cc581b13ee3ce85cf6496e4593e9403ea65b6850400b4a05bb807ee32d298b46fd6e1", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "88768586b19272fff8d1dc6c96df697e94640a6a225410022500f5c13b702e298b46ff588ca47e561cc581c13a075d79af6496df3dbf4a320535112a080169403d704edc1094c5a37fda0f0d8365b7dbe5", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "88c1fbc5df6c96df697e94640a6a225410022500f5c13971a7d4c5a37f0f0d830bcdbf588ca47e561cc581c13a075d6ddf6496df3dbf4a320535112a080169403d704e5c6db53168dfdde8", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "48826401c55f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f0f1fcf9d29aee30c169ad78e3219721d7b7ab05a6b62c2d051a0a863c1eca24f0690ac585ee6418f521875a7dc03313ad3e271f89d69f69a6a27182d319645fa23fca4b218682a60e87b6ca8741914ad593f0f0d033331375888a47e561cc5802e036496dc34fd280654d27eea0801128166e340b81794c5a37fe1ec7b8b84842d695b05443c86aa6f6c96e4593e940854cb6d0a0801128266e059b8c854c5a37ff8e8", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "88cae7f5cfbfe80f0d830802d7588ca47e561cc581c13a1081e17f6496df3dbf4a320535112a080169403f7042b820298b46ffe5f0", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88ccf70f1fcf9d29aee30c169ad78e3219721d7b7ab05a6b62c2d051a0a863c1eca24f0690ac585ee6418f521875a7dc03313ad3e271f89d69f69a6a27182d319645fa23fca4b218682a60e87b6ca8741914ad593f0f0d83700f835888a47e561cc5802e3b6496dc34fd280654d27eea0801128166e340b82714c5a37f6196dc34fd280654d27eea0801128166e32edc65f53168dff3c46c96df697e940bca6e2d6a0801128115c6dcb826d4c5a37ffeee", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "88769086b19272b025c4b85f53fae151bcff7f6c96df3dbf4a042a6a2254100225020b807ae09a53168dff0f138ffe47246b3448c8d900e3f238007f3f52848fd24a8f588ca47e561cc58190b6cb80003f6496df3dbf4a09a535112a080165403d7041b8d094c5a37fcaf30f0d8313aebfd9eef9", + "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" + } + ] + }, + { + "seqno": 150, + "wire": "887f2bfdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff35f96497ca58e83ee3412c3569fb50938ec4153070df8567be559871a52324f496a4ff66196dc34fd280654d27eea0801128166e32edc680a62d1bf768320e52f5885aec3771a4b0f0d830b6d37e7", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "88f55f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d83136073fac1", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "88c96c96df697e940b6a612c6a08010a8172e32fdc13aa62d1bf0f1390fe5c682d2cd3e46da2148d352101fcffc8c76496df697e940baa6e2d6a0801654086e34fdc0b2a62d1bfd3fc0f0d8375c0bf5f901d75d0620d263d4c741f71a0961ab4ffce7f3488ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "88d55a839bd9abf36c96c361be940894d444a820044a08171a15c6dc53168dff6196c361be940094d27eea080112816ee01bb8db4a62d1bf6496dc34fd280654d27eea080112816ee01bb8db4a62d1bff2f10f0d8465d642eff055847821039fef", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "887689bf7b3e65a193777b3fc80f0d03333237c3cb", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "88e6dbeac3ee588ca47e561cc581b13ee3ce881f6496e4593e9403ea65b6850400b4a05bb807ee32f298b46f6196dc34fd280654d27eea0801128166e32edc65e53168df0f0d8465c79907c7ee", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "88d1ce4085aec1cd48ff86a8eb10649cbf6496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25fcefac40f0d03333539f8c9", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "88c4ce0f0d03353330c9d1", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "88ec6c96df697e94640a6a225410022500f5c13971a714c5a37fe2ca0f0d8369d13ff1588ca47e561cc581c13a075d6daf6496df3dbf4a320535112a080169403d704e5c6da53168dfd4cdf4", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "88efe4f3f4cc6c96df697e94640a6a225410022500f5c13b719654c5a37f0f0d820b20588ca47e561cc581c13a075e03bf6496df3dbf4a320535112a080169403d704edc69d53168dfd7d0", + "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" + } + ] + }, + { + "seqno": 160, + "wire": "88f26497d07abe94032a693f750400b4a059b8cbb719794c5a37ff54012a5f88352398ac74acb37f0f0d84782fbe0fcad3408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692ff4089f2b511ad51c8324e5f834d96977b05582d43444e6c96e4593e94138a6e2d6a080112807ee32ddc682a62d1bf", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "488264027688aa6355e580ae25c16196dc34fd280654d27eea0801128166e32edc69953168df0f0d01307f1d842507417f0f1fffd8019d29aee30c0e458b4946bc87b63a0a4a0c4eabd454b0393a31a44dbc15c22138db8b884169d0099704e082c5d71a109a7c2bbdf68f700440f2c83ec94189d4104e94d771860722f21ed8e82928313aaf5152c128313aaacdd9d566ff77986641098658030a886c76559ba271a71d7c026d566e81602acdd0aacdd69f038e36e36ab375a7560880c320559bad3ad0990800c34eb4cbce36cb01559baab37557701faf7559beab375141d2ab37eb1d89a8b6451da949ea0aacdd47b559be1103cb20559ba8291352acdfa8be10ab37489f5595566f90f524b525566ed45f08559be3a4b61883559bb61652d9616c559beab37643d23354ab37fc78f0bc7191721d7b7aaacddb0b296cb0b64521e919aa559bfe3c785e38c8b90ebdbd5566ed8832acdf559bb39472506a8aab37ec3d3517d5761e9320a8b50a89b13b614741271d532acdd55dc084110ab37d5665fb3d9240f32dbce07fcf", + "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?" + } + ] + }, + { + "seqno": 162, + "wire": "88c0bf5f87352398ac4c697f0f0d023433bf", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "88d8e20f0d03343833dd6196dc34fd280654d27eea0801128166e32edc69a53168df", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88f6deca6c96df697e940b6a681fa5040089410ae01ab8dbea62d1bf6196c361be940094d27eea0801128172e00171b1298b46ff6496dc34fd280654d27eea0801128172e00171b1298b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d83682d39408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f558475d7822f5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 165, + "wire": "88d26c96c361be940854d03b14100215042b816ee32d298b46ff6196c361be940094d27eea080112817ee361b8cb8a62d1bf6496dc34fd280654d27eea080112817ee361b8cb8a62d1bfc5c40f0d8365e65ac355847197dc7bc27b8b84842d695b05443c86aa6feb", + "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" + } + ] + }, + { + "seqno": 166, + "wire": "88e6f00f0d03333236ebcb", + "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" + } + ] + }, + { + "seqno": 167, + "wire": "88e6f00f0d821045ebcb", + "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" + } + ] + }, + { + "seqno": 168, + "wire": "880f28e1b1288a1861860d19edbaf39b11f9d711aff0f0e6787c3992bc3bb6d1a7878bbbdaa30d78b6209c3f45838831eb7bed4be7a466aa05ec2f7410cbd454fda983cd66b0a88375b57d280656d27eeb08016540b371976e34d298b46ffb5358d33c0c7f4088f2b5761c8b48348f89ae46568e61a00e2cff7f38e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f76035253495886a8eb10649cbfe66496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7798624f6d5d4b27ff2c5d2", + "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" + } + ] + }, + { + "seqno": 169, + "wire": "88d25f8b497ca58e83ee3412c3569f0f0d03313733f40f28eaef00642b8db4f15a182464ad363748fbe18de8e51c8d81f6c250b4dbd232fb8b38e32d01e65f6c0fb61289e7996a265971cfb50be6b3585441b869fa500cada4fdd610022502d5c03b71a694c5a37fda958d33c0c7da921e919aa8172cb294893772d251a2db0abd454fc2640130768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbfee7f09a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7f", + "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\"" + } + ] + }, + { + "seqno": 170, + "wire": "dd6196dc34fd280654d27eea0801128166e32edc6c0a62d1bf768dd06258741e54ad9326e61c5c1f7f01c3d6ceb51652b3d0627ab0b2c1fcce94d771863c78f0b8e496d418f52e43d2c78648c0e496d418f52fe69a3f9fa52f6b83f9d3ab4a97f76b52f6adaa5ee1b46a6fc90ff34089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277ff40f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983fcc64022d315f92497ca589d34d1f6a1271d882a60b532acf7f0f0d03313838", + "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" + } + ] + }, + { + "seqno": 171, + "wire": "88768586b19272ff52848fd24a8fed5585134db6f07f6196dc34fd280654d27eea0801128166e32edc69b53168df6c96d07abe940b4a693f7504008540bd71915c0b8a62d1bf0f0d8369a6857f2788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "88cac9c8c7c6fc0f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983fd4c5c40f0d8369a69f0f28cf21a481c9401034f36b4ad81d59a1b45586d3cdad296375c0bf24600b3f6a487a466aa05c724b6a0c7a9721e9fb50be6b3585441c8b27d2800ad94752c20080a01cb8005c0014c5a37fda958d33c0c7", + "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=/" + } + ] + }, + { + "seqno": 173, + "wire": "88c3c2e655847596c2ffc16c96c361be94101486bb1410022502ddc6c171b754c5a37f0f0d830ba07fc0", + "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" + } + ] + }, + { + "seqno": 174, + "wire": "88c5c4f355850ba275e6ffc36c96e4593e94109486d99410022502edc6deb8d3ca62d1bf0f0d83680cb9c2", + "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" + } + ] + }, + { + "seqno": 175, + "wire": "88c7c6f555840880fbc0c56c96c361be940094be522820042a08371b0dc6df53168dff0f0d8369f0bfc4", + "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" + } + ] + }, + { + "seqno": 176, + "wire": "88c9deec5a839bd9ab6c96d07abe9403ea65b68504008940b7700fdc1094c5a37f588ca47e561cc581b13ee3ce85af6496e4593e9403ea65b6850400b4a05bb807ee32f298b46fef0f0d830844f7c84084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 177, + "wire": "895f911d75d0620d263d4c795ba0fb8d04b0d5a7e4c36496d07abe940054ca3a940bef814002e001700053168dfff20f0d0130cb58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 178, + "wire": "88d2e76c96df697e940894cb6d0a08010a816ee36fdc0894c5a37fd2c70f0d82101d5f87352398ac5754df588ca47e561cc5804eb4179f13ff6496d07abe940b8a6e2d6a0801654106e36fdc6d953168dff8d1", + "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" + } + ] + }, + { + "seqno": 179, + "wire": "88d66c96c361be94138a6a225410022502fdc6ddb82694c5a37feccb0f0d841380107f5f88352398ac74acb37f588ca47e561cc581c134065c13ff6496dd6d5f4a09c535112a08016940bf71b7ae05a53168dfd7d5ca", + "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" + } + ] + }, + { + "seqno": 180, + "wire": "88769086b19272b025c4b85f53fae151bcff7ff05898a47e561cc5819003e94aed8e8313e9442d48fc8e62c011035f901d75d0620d263d4c741f71a0961ab4ffd16196dc34fd280654d27eea0801128166e32edc13ca62d1bf4088ea52d6b0e83772ff8d49a929ed4c0dfd2948fcc0f3626496dc34fd280654d27eea0801128166e342b82794c5a37fdf0f1390fe5e6db02cd11d91e91d7e379c203f9f6c96e4593e94109486d994100225021b816ae042a62d1bff0f0d840882f07f7f1d88cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 181, + "wire": "88c56c96e4593e94109486d994100225021b816ae05953168dff0f1390fe5908df59a23b23d23b18c11b40fe7fe2c56496dc34fd280654d27eea0801128166e32f5c65953168dff9d80f0d83132e355f86497ca582211f6196dc34fd280654d27eea0801128166e32edc69c53168dfe1", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "88e65f961d75d0620d263d4c7441eafb24e3b1054c1c37e159ef54012a409419085421621ea4d87a161d141fc2d495339e447f95d7ab76ffa53160dff4a6be1bfe94d5af7e4d5a777f409419085421621ea4d87a161d141fc2d3947216c47f99bc7a925a92b6ff5597e94fc5b697b5a5424b22dc8c99fe94f90f0d82085d5887a47e561cc5801f6196dc34fd280654d27eea0801128166e32edc69d53168dfe7", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "88cf6c96e4593e94109486d994100225021b816ae01e53168dff0f138ffe4411156688ec8f48eb92100007f3ec588ca47e561cc58190b6cb80003f6496df697e940baa6e2d6a0801654086e360b8cbea62d1bf7b8b84842d695b05443c86aa6fe40f0d8379a7dadac2eb", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "886196dc34fd280654d27eea0801128166e32edc6dd53168dff16495dc34fd2800a994752820000a0017000b800298b46fde5886a8eb10649cbf7f39caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f0d0234337f11842507417f5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 185, + "wire": "88f6c4e0ea6c96d07abe9403ea65b68504008940b7700fdc132a62d1bf588ca47e561cc581b13ee3ce3adf6496e4593e9403ea65b6850400b4a05bb807ee044a62d1bfc60f0d82089cf4e9", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "887689bf7b3e65a193777b3fe90f0d03353735ee6196dc34fd280654d27eea0801128166e32edc6de53168df", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "48826402768c86b19272ad78fe8e92b015c30f1ffff3019d29aee30c535ae3ae92c72ae43d2c0e4625a580b2000567997197d6109d71b583fe535a6079b640ebff14d7dc904e94d771860722f21ed8e82928313aaf5152c128313aaacdd9d566ff77986641098658030a886c77559ba271a71a03adb2ab3740b01566e81566ebacb8dbed81c559bacb4db4b3a27987c0ab375a75b13416db61a75b65f71d6580aacdd559baabb80fd7baacdf559ba8a0e9559bf4147216c8ce3b24559ba8f6ab37dd13de5f02a2bcfba0f2e38a8af3ee83cbe054579f741e44d81566ea0a44d4ab37ea2f842acdd227d565559be43d492d49559bb517c21566ff83d9448ab376c2ca5b2c2d8ab37ea2f84783d94496a083a8720c40081a7c4faacdd90f48cd52acdff1e3c2f1c645c875edeaab376c2ca5b2c2d91487a466a9566ff8f1e178e322e43af6f5559bb620cab37d566ece51c941aa2aacdf8cf4c7d4d4508ac7d4c848ea3567a0c9310c3a9566eaaee042088559beab32fc4e742601d09947652bd2590c3ae82f95c87a7f0f0d0130c0", + "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" + } + ] + }, + { + "seqno": 188, + "wire": "88c0fd6c96e4593e940054d03b141000e2816ee059b8db8a62d1bf52848fd24a8f0f0d0234335896a47e561cc5801f4a547588324e5837152b5e39fa98bf6496dc34fd280654d27eea0801128166e32edc6de53168df7f218e49a929ed4c0107d2948fcc0175cfdeca", + "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" + } + ] + }, + { + "seqno": 189, + "wire": "88c6f10f0d03333431f6c5", + "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" + } + ] + }, + { + "seqno": 190, + "wire": "887f0dfdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff35f96497ca58e83ee3412c3569fb50938ec4153070df8567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb59871a52324f496a4f5a839bd9ab6196dc34fd280654d27eea0801128166e32edc6df53168df768320e52f5885aec3771a4b0f0d830b2f3b408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f", + "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" + } + ] + }, + { + "seqno": 191, + "wire": "88768586b19272ff6c96dc34fd280654d27eea0801128072e360b8d3aa62d1bfdbc40f0d8369d037f3588ca47e561cc581c640d3ae081f6496d07abe94032a693f750400b4a01cb8d86e32f298b46fd27f1988ea52d6b0e83772ff4084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 192, + "wire": "d3c7c37f0dbcacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa64d37d4e1a72297b568534c3c7f9f0f28c7dd04c16bb9d6682cac165b0bed3ef3af85a6d6f43fb5243d2335502e3ae92c72ae43d3f6a5634cf031f6a17cd66b0a88341eafa500cada4fdd61002d28166e32edc6df53168dff0f1ffffa019d29aee30c0e84ca3b295e92c861d7417cae43d2c0e4625a580b2000567997197d6109d71b583fe535a6079b640ebff14d7dc904e94d771860722f21ed8e82928313aaf5152c128313aaacdd9d566ff77986641098658030a886c77559ba271a71a03adb2ab3740b01566e81566ebacb8dbed81c559bacb4db4b3a27987c0ab375a75b13416db61a75b65f71d6580aacdd559baabb80fd7baacdf559ba8a0e9559bf4147216c8ce3b24559ba8f6ab37dd13de5f02a2bcfba0f2e38a8af3ee83cbe054579f741e44d81566ea0a44d4ab37ea2f842acdd227d565559be43d492d49559bb517c21566ff83d9448ab376c2ca5b2c2d8ab37ea2f84783d94496a083a8720c40081a7c4faacdd90f48cd52acdff1e3c2f1c645c875edeaab376c2ca5b2c2d91487a466a9566ff8f1e178e322e43af6f5559bb620cab37d566ece51c941aa2aacdf8cf4c7d4d4508ac7d4c848ea3567a0c9310c3a9566eaaee042088559beab32fc547889d222401f8b6b41a481b69b69e6c0e89a6430f0d8274217f0f8749a929ed4c0dffef5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f", + "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" + } + ] + }, + { + "seqno": 193, + "wire": "d6d55886a8eb2127b0bf4085aec1cd48ff86a8eb10649cbf640130c30f28c0a4fd0ecc0164000dc109d71bfb50be6b3585441badabe9412da4fdd61002d28172e09eb810298b46ffb52b1a67818fb5243d2335502f496430eba0be5721e9fb0f1fffa8029d29aee30c1a9997a4b21875d05f2b90f4b043d492d49600c0590002c3a27bcbe0880f81b08a2d1c77c5b923aa41d922f3a69a3fca6b27580742651d94af496430eba0be5721e954584722a2c24eaa8b08590002b3ccb8cbeb084eb8dac1559c34d69559bef36c81d7fe29ad303cdb2075ff8a6bee48274a6bb8c30391790f6c741494189d57a8a96094189d5566eceab37fbbcc332084c32c018544363baacdd138d38d01d6d9559ba0580ab3740ab375d65c6df6c0e2acdd65a6da59d13cc3e0559bad3ad89a0b6db0d3adb2fb8eb2c05566eaacdd55dc07ebdd566faacdd45074aacdfa0a390b64671d922acdd47b559bee89ef2f81515e7dd07971c54579f741e5f02a2bcfba0f226c0ab37505226a559bf517c21566e913eab2aacdf21ea496a4aacdda8be10ab37fc1eca24559bb61652d9616c559bf517c23c1eca24b5041d4390620040d3e27d566ec87a466a9566ff8f1e178e322e43af6f5559bb61652d9616c8a43d23354ab37fc78f0bc7191721d7b7aaacddb106559beab376728e4a0d515566fc67a63ea6a284563ea6424751ab3d06498861d4ab3755770210442acdf55997f0f0d0130da", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "88cdc96c96df697e9403ea6a225410022502cdc65ab8d814c5a37f0f1394fe46dca2009665b75668918c0e39295d13c0fe7fd70f0d83089e6fc3f45f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f", + "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" + } + ] + }, + { + "seqno": 195, + "wire": "88dd5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d8313617bd1d0", + "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" + } + ] + }, + { + "seqno": 196, + "wire": "88debe0f0d03333339d1d0", + "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" + } + ] + }, + { + "seqno": 197, + "wire": "88cce8e2d16c96dc34fd280654d27eea080112810dc139700fa98b46ff588ca47e561cc581c640e34271ff6496d07abe94032a693f750400b4a043704fdc03aa62d1bfe00f0d840bcd09ffcbca", + "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" + } + ] + }, + { + "seqno": 198, + "wire": "88e1c10f0d03333332d4d3", + "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" + } + ] + }, + { + "seqno": 199, + "wire": "88d8d3c56496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25fc3d8e30f0d03333332d2d6", + "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" + } + ] + }, + { + "seqno": 200, + "wire": "88e3c30f0d03333339d6d5", + "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" + } + ] + }, + { + "seqno": 201, + "wire": "88d16496dc34fd280654d27eea0801128166e32edc6db53168dff65f87497ca589d34d1f0f0d8479a109cf6196dc34fd280654d27eea0801128166e32edc6db53168dfd0408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692ff4089f2b511ad51c8324e5f834d96977b05582d43444e", + "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" + } + ] + }, + { + "seqno": 202, + "wire": "88e8cf58b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007f6495dc34a9a4fdd4032a059b8cbb71b7d4e1bef2820045e07f16afbdae0fe74eac8a5ee1b46a437f40d4bf8388d4df0e41a9ab86d52ef0dca64d37d4e1a72297b568534c3c54c9a77ff35f91497ca589d34d1f649c7620a98386fc2b3d0f0d83089d67e1", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88efcf0f0d821045e2e1", + "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" + } + ] + }, + { + "seqno": 204, + "wire": "ed6196dc34fd280654d27eea0801128166e32f5c036a62d1bf768dd06258741e54ad9326e61c5c1f7f02c3d6ceb51652b3d0627ab0b2c1fcce94d771863c78f0b8e496d418f52e43d2c78648c0e496d418f52fe69a3f9fa52f6b83f9d3ab4a97f76b52f6adaa5ee1b46a6fc90ff34089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277fd80f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983ffb64022d315f92497ca589d34d1f6a1271d882a60b532acf7f0f0d033138380f28cf21a481c9401034f36b4ad81d59a1b45586d3cdad296375c0bf24600b3f6a487a466aa05c724b6a0c7a9721e9fb50be6b3585441c8b27d2800ad94752c20080a01cb8005c0014c5a37fda958d33c0c7", + "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=/" + } + ] + }, + { + "seqno": 205, + "wire": "880f28fab1288a1861860d19edbaf39b11f9d711aff0f0e6787c3992bc3bb6d1a7878bbbdaa34d78760367099ad52e126cd81e3f937e5187171af25741b2385bad17379bbd3f6e85f1fbe707da97cf48cd540bd85ee82197a8a9fb53079acd615106eb6afa500cada4fdd61002ca8166e32f5c0014c5a37fda9ac699e0634088f2b5761c8b48348f89ae46568e61a001583f7f04e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f76035253495886a8eb10649cbfde6496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7798624f6d5d4b27ff07b8b84842d695b05443c86aa6ff0", + "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" + } + ] + }, + { + "seqno": 206, + "wire": "88768c86b19272ad78fe8e92b015c3e3d1d0f2cfd80f0d8375975bf1", + "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" + } + ] + }, + { + "seqno": 207, + "wire": "88cdcccbcac9e30f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983fc3c8c70f0d8369a69f0f28cf21a481c9401034f36b4ad81d59a1b45586d3cdad296375c0bf24600b3f6a487a466aa05c724b6a0c7a9721e9fb50be6b3585441c8b27d2800ad94752c20080a01cb8005c0014c5a37fda958d33c0c7", + "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=/" + } + ] + }, + { + "seqno": 208, + "wire": "885f88352398ac74acb37f0f0d846dc7822fea6196dc34fd280654d27eea0801128115c69bb80654c5a37f769186b19272b025c4bb2a7f578b52756efeff6c96dc34fd28179486d99410022500e5c0357196d4c5a37f0f1395fe5b90038c6d2d248522cd11d79a04807082203f9f52848fd24a8f5889a47e561cc58197000f6496dc34fd280654d27eea0801128166e34ddc032a62d1bf4097f2b565b29325259162587421690f48cd52d59e8310c54703616c6c5583642ebb4089f2b0e9f6b12558d27fadd3dbbd0ecf24e1fdc97d6457d3433a37748aca7be5b35474245db9cefeccc3d6d43c3b2d95d7d6e17479a6820f7caf0ae05257dd081d75e91979e940e34dca58d96e370a469e9190b8b9283db24b61ea4af5152a7f57a83db261b0f527fb4085f2b10649cb8ec664a92d87a542507b6496c3d49f", + "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" + } + ] + }, + { + "seqno": 209, + "wire": "886196dc34fd280654d27eea0801128166e32f5c0014c5a37f5f8b497ca58e83ee3412c3569f0f0d03313733f70f28eaef03618e52471b6c81b78251caf3457df0c6f4728e46c0fb61285a6de9197dc59c719680f32fb607db095979e65a89965c73ed42f9acd615106e1a7e94032b693f7584008940b5700f5c0014c5a37fda958d33c0c7da921e919aa8172cb294893772d251a2db0abd454fd1f0768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbff47f17a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7f", + "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\"" + } + ] + }, + { + "seqno": 210, + "wire": "89f1d15a839bd9ab6496d07abe940054ca3a940bef814002e001700053168dff6196dc34fd280654d27eea0801128166e32edc6df53168df0f0d0130408721eaa8a4498f5788ea52d6b0e83772ff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bffa", + "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" + } + ] + }, + { + "seqno": 211, + "wire": "88768586b19272ff5f961d75d0620d263d4c7441eafb24e3b1054c1c37e159ef54012a409419085421621ea4d87a161d141fc2d495339e447f95d7ab76ffa53160dff4a6be1bfe94d5af7e4d5a777f409419085421621ea4d87a161d141fc2d3947216c47f99bc7a925a92b6ff5597e94fc5b697b5a5424b22dc8c99fe94f90f0d8208435888a47e561cc58190ffcec5", + "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" + } + ] + }, + { + "seqno": 212, + "wire": "88c3dc5f86497ca582211fc96c96df697e94640a6a225410022500f5c13b702fa98b46ff588ca47e561cc581c13a075d71af6496df3dbf4a320535112a080169403d704edc640a62d1bf6196dc34fd280654d27eea0801128166e32f5c038a62d1bf0f0d03323937ca4084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "88bfc96c96e4593e940054d03b141000e2816ee059b8db8a62d1bfdd0f0d0234335896a47e561cc5801f4a547588324e5837152b5e39fa98bf6496dc34fd280654d27eea0801128166e32f5c038a62d1bf4088ea52d6b0e83772ff8e49a929ed4c0107d2948fcc01705f7f1088cc52d6b4341bb97f5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 214, + "wire": "88cfe85f911d75d0620d263d4c795ba0fb8d04b0d5a7d56c96df3dbf4a044a65b6850400894082e005702fa98b46ff588ca47e561cc581b65a79d759776496df697e940b6a65b6850400b4a05bb8205c134a62d1bf6196dc34fd280654d27eea0801128166e32f5c03aa62d1bf0f0d8375f71fd6c9", + "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" + } + ] + }, + { + "seqno": 215, + "wire": "88d46c96c361be940094d27eea0801128172e085719754c5a37feeda0f0d8369e6c5ec588ca47e561cc581c13efb6eb8e76496dd6d5f4a004a693f750400b4a05cb8276e32ca98b46fc1d9cc", + "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" + } + ] + }, + { + "seqno": 216, + "wire": "88d7f0eeccdc6c96c361be940094d27eea0801128266e059b806d4c5a37f0f0d8371b69e588ca47e561cc581c6402032d33f6496dd6d5f4a004a693f750400b4a099b8176e040a62d1bfc4dc", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "88daf3f1df6c96df3dbf4a002a693f75040089403d700d5c0bea62d1bf588ca47e561cc581c13cf01965ff6496dc34fd2800a9a4fdd41002d2807ae099b8d38a62d1bfc70f0d83682d35df", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "88ddf6f4e26c96df3dbf4a002a693f7504008940b57000b8d894c5a37f0f0d8365d703588ca47e561cc581c13e00804dff6496dc34fd2800a9a4fdd41002d2816ae01eb8c894c5a37fcae2", + "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" + } + ] + }, + { + "seqno": 219, + "wire": "88e0f76c96df3dbf4a002a693f7504008940bd7042b806d4c5a37f0f0d8371c003588ca47e561cc581c13e171e103f6496dc34fd2800a9a4fdd41002d2817ae321b8d3aa62d1bfcde5", + "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" + } + ] + }, + { + "seqno": 220, + "wire": "887689bf7b3e65a193777b3fd20f0d03343534e9ce", + "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" + } + ] + }, + { + "seqno": 221, + "wire": "88e47b8b84842d695b05443c86aa6f5f88352398ac74acb37fdbeb6c96c361be940094d27eea080112816ae32fdc138a62d1bf0f0d8371e6c3588ca47e561cc581c13ef3ec883f6496dd6d5f4a004a693f750400b4a05ab8d02e01e53168dfd3eb", + "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" + } + ] + }, + { + "seqno": 222, + "wire": "88e9c2c1ee6c96df3dbf4a09b535112a080112810dc13b71b714c5a37f0f0d836da087588ca47e561cc581c132203af0bf6496dc34fd2826d4d444a82005a5040b8dbb71a7d4c5a37fd6ee", + "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" + } + ] + }, + { + "seqno": 223, + "wire": "48826402768c86b19272ad78fe8e92b015c30f1fffbf029d29aee30c1a9997a4b21875d05f2b90f4b043d492d49600c05e7c2e319f7c5f9a33c5b4692ef1c74162dc4b0f4506aa6c651c941aa2c5aedb2ba0b0d961fc222da521ec9339fc222744f797c1101b004225fa23fca6b27580742651d94af496430eba0be5721e954584722a2c24eaa8b085e7c2e2c165969d12cc89e71c59e559c34d69559bef38275c77e29ad303ce09d71df8a6bee48274a6bb8c30391790f6c741494189d57a8a96094189d5566eceab37fbbcc332084c32c018544360eab3744e34d3416dd79566e81602acdd02acdd0be17dc784e2acdd65a6da59d13cc3e0559bad3ef8196de0b0d3ef3edb427d80aacdd559baabb80fd7baacdf559ba8a0e9559bf4147216c8ce3b24559ba8f6ab37dd13de5f02a2bcfba0f2e38a8af3ee83cbe054579f741e44d81566ea0a44d4ab37ea2f842acdd227d565559be6aa42f9559bb517c21566ff83d9448ab376c2ca5b2c2d8ab37ea2f84783d9448341862005f032cbaab37643d23354ab37fc78f0bc7191721d7b7aaacddb0b296cb0b64521e919aa559bfe3c785e38c8b90ebdbd5566ed8832acdfca079d78310401644ab376c419566fe503cebc18820704f2acdd55dc084110ab37d5665f0f0d0130d85886a8eb2127b0bf4085aec1cd48ff86a8eb10649cbf6401307f38bcacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa64d37d4e1a72297b568534c3c7f9f0f28c9a4fd0ecc0179f0b971913ce38c0590003704275c6fed42f9acd615106eb6afa504b693f758400b4a05cb8db3700fa98b46ffb52b1a67818fb5243d2335502f496430eba0be5721e9fb", + "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;" + } + ] + }, + { + "seqno": 224, + "wire": "88dcf26495dc34fd2800a994752820000a0017000b800298b46fc15886a8eb10649cbf7f01caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f0d0234337f26842507417fe5", + "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" + } + ] + }, + { + "seqno": 225, + "wire": "88e0f66c96df697e940054d03f4a080112817ee05bb8d014c5a37f0f1394fe4410be40ac16c4e2cd46594ae36eb6d4a007f352848fd24a8f0f0d8371f7817f2a8749a929ed4c0dffe9e7", + "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" + } + ] + }, + { + "seqno": 226, + "wire": "88f96496dc34fd280654d27eea0801128166e32f5c036a62d1bff85f87497ca589d34d1f0f0d847c0e38e76196dc34fd280654d27eea0801128166e32f5c036a62d1bf7f0588ea52d6b0e83772ff408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692ff4089f2b511ad51c8324e5f834d96977b05582d43444e", + "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" + } + ] + }, + { + "seqno": 227, + "wire": "88768586b19272ff6c96e4593e940bea6a225410021500edc13d7197d4c5a37ff9dd5a839bd9ab0f0d840bccb6ffdd588ca47e561cc581b132d3ecb2f76496e4593e940094cb6d0a0801694086e01db806d4c5a37ff1c8", + "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" + } + ] + }, + { + "seqno": 228, + "wire": "88c2e0dfc06c96c361be940094d27eea080112817ae05fb82694c5a37f588ca47e561cc581c6400136cb5f6496dd6d5f4a004a693f750400b4a05eb8205c1054c5a37ff40f0d836dd7c3cb4084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 229, + "wire": "88c66c96dc34fd280654d27eea080112807ee320b8d3aa62d1bfe5c50f0d836c0cb7e4588ca47e561cc581c640dbac801f6496d07abe94032a693f750400b4a01fb8cb3700ea98b46ff8cfc1", + "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" + } + ] + }, + { + "seqno": 230, + "wire": "88c9e7e6c76c96c361be940094d27eea0801128072e36ddc684a62d1bf588ca47e561cc581c13ee05b743f6497dd6d5f4a004a693f750400b4a01cb8dbb719794c5a37fffb0f0d83704e39d2", + "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" + } + ] + }, + { + "seqno": 231, + "wire": "88cce96c96e4593e94642a6a225410022502ddc6d9b8cbaa62d1bf0f0d8369d6dd588ca47e561cc581c13c203ef39f6496c361be94642a6a22541002d2816ee36d5c65953168df6196dc34fd280654d27eea0801128166e32f5c03aa62d1bfd6", + "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" + } + ] + }, + { + "seqno": 232, + "wire": "88d0eeedce6c96df3dbf4a002a693f75040089403f7001b8d094c5a37f588ca47e561cc581c13cf09d083f6496dc34fd2800a9a4fdd41002d2807ee019b81754c5a37fc10f0d836d97dcd9", + "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" + } + ] + }, + { + "seqno": 233, + "wire": "88d3f1f0cbd16c96c361be940094d27eea080112807ae01fb8c814c5a37f0f0d8369d6df588ca47e561cc581c13ee36fb2d76496dd6d5f4a004a693f750400b4a01eb8105c1054c5a37fc4dc", + "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" + } + ] + }, + { + "seqno": 234, + "wire": "88d6f4f3d46c96c361be940094d27eea0801128166e09ab81754c5a37f0f0d83644017588ca47e561cc581c13ef3ee01df6497dd6d5f4a004a693f750400b4a05ab8d3571b694c5a37ffc7df", + "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" + } + ] + }, + { + "seqno": 235, + "wire": "88d96c96c361be940094d27eea0801128166e003704da98b46ffd2f8d80f0d83680217f7588ca47e561cc581c13ef32e09df6496dd6d5f4a004a693f750400b4a059b806ee05b53168df6196dc34fd280654d27eea0801128166e32f5c03ca62d1bfe3", + "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" + } + ] + }, + { + "seqno": 236, + "wire": "88ddfbfadb6c96c361be940094d27eea080112807ae36d5c6db53168df588ca47e561cc581c13ee802f03f6496dd6d5f4a004a693f750400b4a01fb820dc03ca62d1bfc10f0d8369e6d9e6d8", + "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" + } + ] + }, + { + "seqno": 237, + "wire": "88e06c96df3dbf4a002a693f7504008940b371a6ae01a53168df7b8b84842d695b05443c86aa6fe00f0d83644f3f5f87352398ac4c697f588ca47e561cc581c13e00ba017f6496dc34fd2800a9a4fdd41002d2816ae05fb8d814c5a37fc6ebdd", + "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" + } + ] + }, + { + "seqno": 238, + "wire": "88e5c15f88352398ac74acb37fdee46c96df3dbf4a002a693f7504008940b971b6ee002a62d1bf0f0d8374206f588ca47e561cc581c13e1081f67f6496dc34fd2800a9a4fdd41002d28172e36e5c1014c5a37fd7ef", + "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" + } + ] + }, + { + "seqno": 239, + "wire": "88e9c5c1e76c96c361be940b4a6e2d6a0801128076e36edc65c53168df588ca47e561cc581b79d644cb6ef6496dd6d5f4a05a53716b50400b4a01eb8105c69b53168dfcd0f0d8365f701f2", + "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" + } + ] + }, + { + "seqno": 240, + "wire": "88ecc46c96df697e94105486d99410022500edc65cb8cbaa62d1bf0f0d8365f69e588ca47e561cc581b71c6dc7441f6496df3dbf4a082a436cca080169403b71972e34fa98b46fd0f5", + "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" + } + ] + }, + { + "seqno": 241, + "wire": "88ef6c96df3dbf4a01f5340ec5040038a08371915c642a62d1bf0f1392fe5f95a048b32359a015f71f90426df203f9fb5f911d75d0620d263d4c795ba0fb8d04b0d5a7cdefd20f0d023633f7", + "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" + } + ] + }, + { + "seqno": 242, + "wire": "88f16c96d07abe94036a681d8a0801128115c0b7704ca98b46ffcaeacef00f0d846df7db7b588ca47e561cc581a101d0bce3ff6496e4593e94036a681d8a080169408ae05bb8db8a62d1bfe2fa", + "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" + } + ] + }, + { + "seqno": 243, + "wire": "88f45f8b497ca58e83ee3412c3569f4085aec1cd48ff000f0d033437395888a47e561cc581907fd8fd", + "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" + } + ] + }, + { + "seqno": 244, + "wire": "887689bf7b3e65a193777b3fc50f0d83134fb3f66196dc34fd280654d27eea0801128166e32f5c03ea62d1bf", + "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" + } + ] + }, + { + "seqno": 245, + "wire": "88bfc60f0d826441f7be", + "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" + } + ] + }, + { + "seqno": 246, + "wire": "884003703370fdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff3bf7f0386a8eb10649cbf6496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25fca4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbc40f0d03333633408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 247, + "wire": "88c6cd0f0d821045bec5", + "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" + } + ] + }, + { + "seqno": 248, + "wire": "488264026196dc34fd280654d27eea0801128166e32f5c0b4a62d1bf768dd06258741e54ad9326e61c5c1f7f08c3d6ceb51652b3d0627ab0b2c1fcce94d771863c78f0b8e496d418f52e43d2c78648c0e496d418f52fe69a3f9fa52f6b83f9d3ab4a97f76b52f6adaa5ee1b46a6fc90ff34089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277fc90f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983f5886a8eb10649cbf64022d315f92497ca589d34d1f6a1271d882a60b532acf7f0f0d033138380f28cf21a481c9401034f36b4ad81d59a1b45586d3cdad296375c0bf24600b3f6a487a466aa05c724b6a0c7a9721e9fb50be6b3585441c8b27d2800ad94752c20080a01cb8005c0014c5a37fda958d33c0c7", + "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=/" + } + ] + }, + { + "seqno": 249, + "wire": "88c5c4c3c2c1cc0f1faf9d29aee30c78f1e171c92da831ea5c87a58864dc5b3b96c6242ca3b684ae3457e7fc2c06f8a0d2401038d07e08983fc0bfbe0f0d8369a69f0f28cf21a481c9401034f36b4ad81d59a1b45586d3cdad296375c0bf24600b3f6a487a466aa05c724b6a0c7a9721e9fb50be6b3585441c8b27d2800ad94752c20080a01cb8005c0014c5a37fda958d33c0c7", + "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=/" + } + ] + }, + { + "seqno": 250, + "wire": "88cd5f96497ca58e83ee3412c3569fb50938ec4153070df8567bca59871a52324f496a4fc9d0768320e52f5885aec3771a4b0f0d830b2fb9cc", + "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" + } + ] + }, + { + "seqno": 251, + "wire": "880f28fbb1288a1861860d19edbb336ffe78a18c1835070f0db7616490d1353523fdfef44f0aba7fbd50ddb077f4bd1defdf77e9e93e5c53c79a1f38395d269cfeb5f2e0f51ac7bbdef2b2007da97cf48cd540bd85ee82197a8a9fb53079acd615106eb6afa500cada4fdd61002ca8166e32f5c03ea62d1bfed4d634cf031f4088f2b5761c8b48348f89ae46568e61a00d2c1f7f09e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f7603525349c7d36496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7798624f6d5d4b27fd1efd8", + "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" + } + ] + }, + { + "seqno": 252, + "wire": "88d8dc0f0d03313733408721eaa8a4498f5788ea52d6b0e83772ff0f28eaef0481148db3295a8e465f03efc6191f7c31bd1ca391b03ed84a169b7a465f71671c65a03ccbed81f6c25682f32d44cb2e39f6a17cd66b0a88370d3f4a0195b49fbac20044a05ab807ae01f53168dff6a5634cf031f6a487a466aa05cb2ca5224ddcb49468b6c2af5153cb640130768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbfdb7f08a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7f", + "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\"" + } + ] + }, + { + "seqno": 253, + "wire": "88768586b19272fff6f5d86c96d07abe9403ea65b68504008940b7700fdc1054c5a37f588ca47e561cc581b13ee3ce3ccf6496e4593e9403ea65b6850400b4a05bb807ee32253168dfe20f0d84085f65dfc74084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 254, + "wire": "89ebfadc6496d07abe940054ca3a940bef814002e001700053168dffe40f0d0130c958b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfe3", + "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" + } + ] + }, + { + "seqno": 255, + "wire": "88c46c96df697e94640a6a225410022500f5c13971a654c5a37f5f87352398ac5754dfc27b8b84842d695b05443c86aa6fe10f0d830b6fb5588ca47e561cc581c13a075c7dff6496df3dbf4a320535112a080169403d704e5c13ca62d1bfeacf", + "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" + } + ] + }, + { + "seqno": 256, + "wire": "88c96c96d07abe940b8a65b6850400894102e36d5c0b4a62d1bf0f1395fe5c91c209959e0b8459a2352bc3095c69f781fcff52848fd24a8f0f0d846590b22f5f88352398ac74acb37f6196dc34fd280654d27eea0801128166e32f5c03ca62d1bfd3", + "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" + } + ] + }, + { + "seqno": 257, + "wire": "886196dc34fd280654d27eea0801128166e32f5c1094c5a37fce6495dc34fd2800a994752820000a0017000b800298b46feee27f11caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f0d0234337f17842507417f5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 258, + "wire": "88f4fb0f0d03333137ec6196dc34fd280654d27eea0801128166e32f5c132a62d1bf", + "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" + } + ] + }, + { + "seqno": 259, + "wire": "88f55f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d8308842feebf", + "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" + } + ] + }, + { + "seqno": 260, + "wire": "88c1bfeb7f03a1bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa5de1b94d5bef7f3f54012aeb5f87497ca589d34d1f0f0d8369c6430f28c7d7b6b241ff31d9cfbe3bf883703ff3febee43d2335500e442f59cd526c3d142e43d3f6a5634cf031f6a17cd66b0a88341eafa500cada4fdd61002d28166e32f5c132a62d1bfeff", + "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;" + } + ] + }, + { + "seqno": 261, + "wire": "88d76c96c361be940094d27eea0801128115c659b820a98b46ffcad4cff20f0d840baf32ff588ca47e561cc581c13ef3af361f6496dd6d5f4a004a693f750400b4a05ab816ee36ca98b46fcae0", + "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" + } + ] + }, + { + "seqno": 262, + "wire": "88dad1ccf46c96c361be940094d27eea0801128015c6c371b694c5a37f588ca47e561cc581c13ed38f899f6496dd6d5f4a004a693f750400b4a00571b66e34da98b46fcd0f0d8369e13be3d9", + "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" + } + ] + }, + { + "seqno": 263, + "wire": "88dd6c96c361be940094d27eea080112816ee34f5c682a62d1bfd5f80f0d836de7c3d0588ca47e561cc581c13efb2d3c0f6496dd6d5f4a004a693f750400b4a05bb8d3f71a1298b46fd0e6dc", + "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" + } + ] + }, + { + "seqno": 264, + "wire": "88e0d7d2dcfa6c96c361be940094d27eea0801128105c69ab80694c5a37f0f0d8365c71a588ca47e561cc581c13eeb6c85df6496dd6d5f4a004a693f750400b4a04171a72e36fa98b46fd3e9", + "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" + } + ] + }, + { + "seqno": 265, + "wire": "88e36c96e4593e94642a6a225410022502cdc03d7190a98b46ffe0db5a839bd9ab0f0d836db79fd7588ca47e561cc581c13c165a79df6496c361be94642a6a22541002d28166e34fdc69f53168dfd7ed", + "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" + } + ] + }, + { + "seqno": 266, + "wire": "88e7ded9e3c06c96e4593e94642a6a2254100225021b8d3b704e298b46ff0f0d8371d79d588ca47e561cc581c13c07196dbf6496c361be94642a6a22541002d2810dc6c171b754c5a37fdaf0", + "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" + } + ] + }, + { + "seqno": 267, + "wire": "88d5ea6c96e4593e940054d03b141000e2816ee059b8db8a62d1bfde0f0d0234335896a47e561cc5801f4a547588324e5837152b5e39fa98bf6496dc34fd280654d27eea0801128166e32f5c132a62d1bf4088ea52d6b0e83772ff8e49a929ed4c0107d2948fcc016c1f7f1c88cc52d6b4341bb97fdb", + "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" + } + ] + }, + { + "seqno": 268, + "wire": "88dfef588eaec3771a4bf4a523f2b0e62c0c834089f2b511ad51c8324e5f834d96975f8b497ca58e83ee3412c3569f0f0d0234377f038749a929ed4c0d37c2", + "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" + } + ] + }, + { + "seqno": 269, + "wire": "887689bf7b3e65a193777b3fde0f0d83089917cddf", + "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" + } + ] + }, + { + "seqno": 270, + "wire": "88e1df768dd06258741e54ad9326e61c5c1fdedd4089f2b567f05b0b22d1fa868776b5f4e0dfdd0f0d8369c6dd0f28d0d7b6b241ff31d9cfc63bf881703ff31d9cfbe3bf883703ff3febee43d2335500e442f59cd526c3d142e43d3f6a5634cf031f6a17cd66b0a88341eafa500cada4fdd61002d28166e32f5c132a62d1bfef", + "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;" + } + ] + }, + { + "seqno": 271, + "wire": "88f66c96df3dbf4a09b535112a0801128115c6dab8cb4a62d1bfe9f3eed00f0d83704f3f588ca47e561cc581c109f0bce07f6496dc34fd2826d4d444a82005a5022b8db9700d298b46ffe47f0988ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 272, + "wire": "88faf1ecd36c96df3dbf4a002a693f75040089403771b7ee36053168df588ca47e561cc581c13ce85f71cf6496dc34fd2800a9a4fdd41002d28072e01ab827d4c5a37fe80f0d83680e87c1f9", + "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" + } + ] + }, + { + "seqno": 273, + "wire": "88768586b19272ff6c96df3dbf4a002a693f75040089403f7197ee32fa98b46ff6d80f0d8371e705f1588ca47e561cc581c13cf36069bf6496dc34fd2800a9a4fdd41002d2807ee342b82794c5a37fecc54084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 274, + "wire": "88c26c96d07abe94134a6e2d6a0801128115c69bb8d38a62d1bfbffadc0f0d8368016bf5588ca47e561cc581b7dc089e69bf6496e4593e94134a6e2d6a080169408ae34ddc69e53168dff0c9", + "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" + } + ] + }, + { + "seqno": 275, + "wire": "88cfef0f0d03333630def0", + "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" + } + ] + }, + { + "seqno": 276, + "wire": "88c5fcf7c1de6c96c361be940094d27eea080112806ee0457196d4c5a37f0f0d8371d745588ca47e561cc581c13edb6f36ef6496dd6d5f4a004a693f750400b4a01bb8215c680a62d1bff3cc", + "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" + } + ] + }, + { + "seqno": 277, + "wire": "887f32fdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff3f44085aec1cd48ff86a8eb10649cbf6496c361be940054ca3a940bef814002e001700053168dff5892a8eb10649cbf4a536a12b585ee3a0d20d25ff64090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbd70f0d03353438408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275fe7", + "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" + } + ] + }, + { + "seqno": 278, + "wire": "88d8f80f0d03353435e76196dc34fd280654d27eea0801128166e32f5c134a62d1bf", + "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" + } + ] + }, + { + "seqno": 279, + "wire": "88d9f90f0d03353435e8be", + "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" + } + ] + }, + { + "seqno": 280, + "wire": "887b8b84842d695b05443c86aa6fe95f88352398ac74acb37f6c96df697e940054c258d410021502e5c69bb81754c5a37f6196c361be940094d27eea080112817ee34fdc1054c5a37f6496dc34fd280654d27eea080112817ee34fdc1054c5a37fc5768344b2970f0d8369a69dc5558471a0b4cf5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 281, + "wire": "885f87352398ac4c697f6c96df697e94136a6e2d6a0801128205c65db810a98b46ff6196c361be940094d27eea0801128205c0b571b694c5a37f6496dc34fd280654d27eea0801128205c0b571b694c5a37fccc40f0d8313efb3cb5584704e041fc3caf5", + "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" + } + ] + }, + { + "seqno": 282, + "wire": "88dc6496dc34fd280654d27eea0801128166e32f5c1054c5a37f54012a5f87497ca589d34d1f0f0d85081979c07f6196dc34fd280654d27eea0801128166e32f5c1054c5a37fe4408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692fff07b05582d43444e", + "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" + } + ] + }, + { + "seqno": 283, + "wire": "88d2fd5f87352398ac5754df6c96d07abe941094d444a820044a05eb8db371a1298b46ff6196c361be940094d27eea080112820dc6dfb8c894c5a37f6496dc34fd280654d27eea080112820dc6dfb8c894c5a37fd9d10f0d836dc0bfd855846dc65917d0", + "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" + } + ] + }, + { + "seqno": 284, + "wire": "88c26c96d07abe941094d444a820044a05eb8db5719794c5a37f6196c361be940094d27eea080112820dc6dfb8cb2a62d1bf6496dc34fd280654d27eea080112820dc6dfb8cb2a62d1bfddd50f0d836d975fdc55846dc6590fd4db5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 285, + "wire": "488264027686c58703025c1f5f92497ca589d34d1f6a1271d882a60e1bf0acf70f0d0130c1e00f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2f5886a8eb10649cbfe6", + "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" + } + ] + }, + { + "seqno": 286, + "wire": "c1e7e1e6e5bebfe3c00f0d0130e2c20f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2f", + "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" + } + ] + }, + { + "seqno": 287, + "wire": "88e0c2d86c96c361be94036a693f7504008140bd7021b8cb4a62d1bf6196dc34fd280654d27eea080112807ae05ab806d4c5a37f6496dd6d5f4a01a5349fba820044a01eb816ae01b53168dfe6de0f0d023433e555840bed36ffdd", + "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" + } + ] + }, + { + "seqno": 288, + "wire": "88768dd06258741e54ad9326e61c5c1f7f2da1bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa5de1b94d5bef7f3fd84089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277f5f87497ca58ae819aa0f0d8365b13d5891aec3771a4bf4a523f2b0e62c0d81c71f6b6196dc34fd280654d27eea0801128166e32f5c132a62d1bf408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 289, + "wire": "88f35f96497ca58e83ee3412c3569fb50938ec4153070df8567bf059871a52324f496a4fd0ef768320e52f5885aec3771a4b0f0d03383832f2", + "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" + } + ] + }, + { + "seqno": 290, + "wire": "88768586b19272fff1f0d36c96c361be940094d27eea0801128076e322b81714c5a37f588ca47e561cc581c13ee32eb20f6497dd6d5f4a004a693f750400b4a01db8cb371b654c5a37ffc70f0d83702117c64084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 291, + "wire": "88c26c96c361be940094d27eea0801128015c6d9b800298b46fff6d80f0d8371f035f5588ca47e561cc581c13ed3a06dff6496dd6d5f4a004a693f750400b4a00571b72e004a62d1bfcbcac1", + "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" + } + ] + }, + { + "seqno": 292, + "wire": "88c5f8f7c1da6c96d07abe9413ea6a225410022504cdc6dab8cbca62d1bf0f0d8371a71d588ca47e561cc581c138ebacb8ff6496df3dbf4a320535112a0801694002e003702253168dffcecd", + "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" + } + ] + }, + { + "seqno": 293, + "wire": "88c8fbfac4dd6c96c361be940094d27eea080112800dc6dcb8d34a62d1bf0f0d836dd7c1588ca47e561cc581c13ed32fb2ef6496dd6d5f4a004a693f750400b4a005700d5c0014c5a37fd1d0", + "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" + } + ] + }, + { + "seqno": 294, + "wire": "88cbfd6c96df3dbf4a05b52f948a08010a810dc68571b7d4c5a37f0f0d840b2171cf588ca47e561cc581c0321136eb3f6496df3dbf4a004a6a22541002d2816ee01db8db8a62d1bfd4d3", + "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" + } + ] + }, + { + "seqno": 295, + "wire": "88ceff02ff01e36c96c361be940094d27eea080112817ee34edc0054c5a37f0f0d8371d0b7588ca47e561cc581c640075d7daf6496dd6d5f4a004a693f750400b4a05fb8d3d702ea98b46fd7d6", + "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" + } + ] + }, + { + "seqno": 296, + "wire": "88588da8eb10649cbf4a54759093d85f4085aec1cd48ff86a8eb10649cbf0f0d023432fe6496dd6d5f4a01b5b2db52c2001b5042b8005c0014c5a37f0f28d6b450008191b75d12ce8dd6d669f0b2b3e565a59f0c61291970ae3ae33b3b82307da85f359ac2a20c361be940056c258d61002ca807ee32f5c134a62d1bfed490f48cd540ba0b67735532c8f485c87a7ed4ac699e063ff9de7f2096bdae0fe74eac8a5fc1c46a6ae1b54bbc3729c34e4fe76196dc34fd280654d27eea0801128166e32f5c134a62d1bf7f1c842507417f", + "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" + } + ] + }, + { + "seqno": 297, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d83132e83eec10f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2feac4", + "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" + } + ] + }, + { + "seqno": 298, + "wire": "88d96496d07abe94032a693f750400b4a059b8cbd704d298b46fff005f88352398ac74acb37f0f0d840bafb80fc37f0388cc52d6b4341bb97ffefd588ca47e561cc581c640e880007f4089f2b511ad51c8324e5f834d9697fd6c96d07abe9403ca693f7504008140b571b66e36e298b46f4088ea52d6b0e83772ff8d49a929ed4c0dfd2948fcc0e859", + "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" + } + ] + }, + { + "seqno": 299, + "wire": "887b8b84842d695b05443c86aa6ff65f87352398ac4c697f6c96df3dbf4a09a5340fd2820044a08171b15c038a62d1bf6196c361be940094d27eea0801128205c69bb8c814c5a37f6496dc34fd280654d27eea0801128205c69bb8c814c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d840bccbaef408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5584700ebad75890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 300, + "wire": "880f28fbb1288a1861860d19edbb336ffe78a18c1835070f0db7616490d1353523fdfecfe66c3fa2fc904f56d697bfdf6199fed8ffdf7fcc09cbd7439a5987de6bdb505ba7a70faf6e318c14fda97cf48cd540bd85ee82197a8a9fb53079acd615106eb6afa500cada4fdd61002ca8166e32f5c134a62d1bfed4d634cf031f4088f2b5761c8b48348f89ae46568e61a00fac1f7f15e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f7603525349fed86496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7798624f6d5d4b27f5a839bd9abced9", + "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" + } + ] + }, + { + "seqno": 301, + "wire": "88f7f16c96d07abe9403ca693f7504008140b571b66e34f298b46f0f0d840bae041fd36496d07abe94032a693f750400b4a059b8cbd704ca98b46f7b05582d43444e54012a7f148e49a929ed4c0dfd2948fcc0ebecffd8d9", + "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" + } + ] + }, + { + "seqno": 302, + "wire": "88de768dd54d464db6154bf79812e05c1fc00f28da445dcd07feef6effe770ffc13cd42f6103e06c2e02fbd75670000003086f00207af5f6bff77b07ff3ed4c1e6b3585441be7b7e94504a693f750400baa059b8cbd704d298b46ffb52f9e919aa81035e38c8b90f4fda9ac699e0634003782d6386a50b34bb4bbf6496c361be940094d27eea0801128166e32f5c134a62d1bf6c96dd6d5f4a01a5349fba820044a059b8cbd704d298b46f58a6a8eb10649cbf4a54759093d85fa5291f9587316007d2951d64d83a9129eca7e94aec3771a4bfe60f1393fe5b03ed8703605830bcd2ce38fe06dcbb7bf97b012a7f0fbbacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee854d5c36a9934df52f6ad0a69878a9bb7c3fcff4086f282d9dcb67f85f1e3c38e370f0d0234337f078749a929ed4c016fe1db", + "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" + } + ] + }, + { + "seqno": 303, + "wire": "88768586b19272ffdde3cd6c96c361be940094d27eea0801128005c03d700e298b46ff588ca47e561cc581c13ecbacbeff6496dd6d5f4a004a693f750400b4a001702ddc032a62d1bfeb0f0d83742f037f2688ea52d6b0e83772ff4084f2b563938d1f739a4523b0fe105b148ed9bf", + "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" + } + ] + }, + { + "seqno": 304, + "wire": "88c36c96e4593e94642a6a225410022502ddc6dab8d054c5a37fe3d30f0d8369f00be9588ca47e561cc581c13cd3c275ef6496c361be94642a6a22541002d28266e09fb8d094c5a37ff0c2c1", + "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" + } + ] + }, + { + "seqno": 305, + "wire": "88c6e5ebc1d56c96df3dbf4a002a693f75040089413371966e36153168df0f0d8365f641588ca47e561cc581c13ecb6269bf6496dc34fd2800a9a4fdd41002d28266e32fdc03ea62d1bff3c5", + "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" + } + ] + }, + { + "seqno": 306, + "wire": "88f35f8b497ca58e83ee3412c3569f0f0d03313733c60f28eaef03a27c212cb215a74b23b24afbed3ef8637a394723607db0942d36f48cbee2ce38cb407997db03ed84ad81e65a89965c73ed42f9acd615106e1a7e94032b693f7584008940b5700f5c134a62d1bfed4ac699e063ed490f48cd540b96594a449bb96928d16d855ea2a75886a8eb10649cbf640130768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbffc7f13a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7f", + "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\"" + } + ] + }, + { + "seqno": 307, + "wire": "88d0f56c96e4593e94642a6a225410022504cdc00ae36ca98b46ff0f0d8365b79f588ca47e561cc581c13cd38fbacf6496c361be94642a6a22541002d28266e01db8dbaa62d1bffdcf", + "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" + } + ] + }, + { + "seqno": 308, + "wire": "88768dd06258741e54ad9326e61c5c1f7f03a1bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa5de1b94d5bef7f3fe04089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277f5f87497ca58ae819aa0f0d840b6dbce75891aec3771a4bf4a523f2b0e62c0d81c71d6f6196dc34fd280654d27eea0801128166e32f5c132a62d1bfd6", + "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" + } + ] + }, + { + "seqno": 309, + "wire": "880f0d841002d87ff86c96df3dbf4a09b535112a0801128176e059b8d34a62d1bf52848fd24a8f0f1390fe40db4d3417246a311240dc8db73f9fc6c5c4c0d8", + "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" + } + ] + }, + { + "seqno": 310, + "wire": "88fafbeb6496d07abe940054ca3a940bef814002e001700053168dff6196dc34fd280654d27eea0801128166e32f5c134a62d1bf0f0d023433da58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 311, + "wire": "88e07b8b84842d695b05443c86aa6f5f88352398ac74acb37ff16c96d07abe94036a681d8a0801128115c102e32ea98b46ff588ca47e561cc581a101d10596ff6496e4593e94036a681d8a080169408ae081719754c5a37f6196dc34fd280654d27eea0801128166e32f5c1094c5a37f0f0d846df7db7be2", + "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" + } + ] + }, + { + "seqno": 312, + "wire": "88e6c35f87352398ac5754dff66c96df697e94640a6a225410022500f5c13971a794c5a37f588ca47e561cc581c13a075d083f6496df3dbf4a320535112a080169403d704e5c6da53168dfca0f0d03313839e6e5", + "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" + } + ] + }, + { + "seqno": 313, + "wire": "88ea6c96c361be94138a6a225410022502ddc0bd71a0a98b46ffc8fa0f0d836da743c7588ca47e561cc581c132f3a0645f6496dd6d5f4a09c535112a08016940b77042b81714c5a37fcde9e8", + "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" + } + ] + }, + { + "seqno": 314, + "wire": "88edcac9e8fc6c96df697e940b6a693f75040085403f71a7ee32ca98b46f0f0d8365c69b588ca47e561cc581b7c4eb6d89bf6496dc34fd282029b8b5a82005a502ddc03371a7d4c5a37fd0ec", + "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" + } + ] + }, + { + "seqno": 315, + "wire": "88f06c96c361be940094d27eea080112800dc641704fa98b46ffecce5a839bd9ab0f0d836df65dce588ca47e561cc581c13ed08400ff6496dd6d5f4a004a693f750400b4a0037196ee01a53168dfd8f0", + "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" + } + ] + }, + { + "seqno": 316, + "wire": "88f4d1d0c06c96c361be940094d27eea0801128176e342b81694c5a37f588ca47e561cc581c6400009f77f6496dd6d5f4a004a693f750400b4a05db8d33704053168dfdb0f0d8371e03bf3", + "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" + } + ] + }, + { + "seqno": 317, + "wire": "88f7d4d3f2c36c96e4593e94642a6a225410022504cdc03371a0298b46ff0f0d83699785588ca47e561cc581c13cd38fb4e76496c361be94642a6a22541002d28266e01db8c814c5a37fdaf6", + "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" + } + ] + }, + { + "seqno": 318, + "wire": "88fad7d6c66c96df697e94640a6a225410022504cdc69fb8dbea62d1bf0f0d836c4fbf588ca47e561cc581c13ae3c271cf6496c361be94642a6a22541002d2800dc0b9702053168dffddf9", + "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" + } + ] + }, + { + "seqno": 319, + "wire": "887f3a842507417f6196dc34fd280654d27eea0801128166e32f5c138a62d1bfe9e8e7e60f0d01315885aec3771a4b5f92497ca58ae819aafb50938ec415305a99567b", + "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" + } + ] + }, + { + "seqno": 320, + "wire": "88c1c0ebeae9e80f0d0131bfbe", + "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" + } + ] + }, + { + "seqno": 321, + "wire": "880f0d8413efb8df5f87352398ac4c697f6c96df3dbf4a09b535112a0801128176e045719694c5a37fe50f1390fe40291e8ca49198c449037236dcfe7fedecebe77f0488ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 322, + "wire": "88c46196dc34fd280654d27eea0801128166e32f5c642a62d1bfefeeedec0f0d0131c3c2", + "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" + } + ] + }, + { + "seqno": 323, + "wire": "88be768586b19272ff6495dc34fd2800a994752820000a0017000b800298b46fe5fa7f31caacf4189eac2cb07f33a535dc618f1e3c2f5164424695c87a58f0c918ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d534e4bea6bdd0a90dfd0a6ae1b54c9a6fa9a61e2a5ed5a3f90f0d023433c8c4", + "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" + } + ] + }, + { + "seqno": 324, + "wire": "88c1c06c96e4593e940054d03b141000e2816ee059b8db8a62d1bfeb0f0d0234335896a47e561cc5801f4a547588324e5837152b5e39fa98bf6496dc34fd280654d27eea0801128166e32f5c642a62d1bf4088ea52d6b0e83772ff8d49a929ed4c0107d2948fcc0f877f0788cc52d6b4341bb97fc9", + "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" + } + ] + }, + { + "seqno": 325, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d826422db6196dc34fd280654d27eea0801128166e32f5c644a62d1bf0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2f5886a8eb10649cbfef", + "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" + } + ] + }, + { + "seqno": 326, + "wire": "88c1c00f0d830882e7ddbf0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fbeef", + "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" + } + ] + }, + { + "seqno": 327, + "wire": "88d1bffbfa54012afa5f87497ca589d34d1f0f0d8369c6430f28d0d7b6b241ff31d9cfc63bf881703ff31d9cfbe3bf883705ff3febee43d2335500e442f59cd526c3d142e43d3f6a5634cf031f6a17cd66b0a88341eafa500cada4fdd61002d28166e32f5c644a62d1bfef", + "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;" + } + ] + }, + { + "seqno": 328, + "wire": "88c3c20f0d826442df6196dc34fd280654d27eea0801128166e32f5c65953168df0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fc1f2", + "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" + } + ] + }, + { + "seqno": 329, + "wire": "88ccf1f0e06c96c361be941014cb6d0a080112810dc6c1704e298b46ff588ca47e561cc581b65f03a1781f6496dd6d5f4a080a65b6850400b4a04371b0dc644a62d1bfc50f0d83105a7fd1", + "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" + } + ] + }, + { + "seqno": 330, + "wire": "887f0efdacf4189eac2cb07f33a535dc61898e79a828e442f32f21ed8e82928313aaf5152c56398a39189895455b35c4bf9a68fe7e94bdae0fe6f70da3521bfa06a5fc1c46a6f8721d4d7ba13a9af75f3a9ab86d53269bea70d3914d7c36a9934ef52fe0d0a6edf0a9af6e052f6ad0a69878a9ab7de534eac8a5fddad4bdab6ff35f96497ca58e83ee3412c3569fb50938ec4153070df8567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb59871a52324f496a4fe7c5768320e52fda0f0d830b8e03408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f", + "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" + } + ] + }, + { + "seqno": 331, + "wire": "88cdcc0f0d03363039e9c70f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fca4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 332, + "wire": "885886a8eb2127b0bfcaeb6401307b8b84842d695b05443c86aa6f4086f2b5281c86938713e164017c2d7fd0e20f0d8313cf0b", + "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" + } + ] + }, + { + "seqno": 333, + "wire": "887684aa6355e7cddf798624f6d5d4b27fde7f178749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37fc6d37f0dd2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 334, + "wire": "88d7d60f0d826440f3d10f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fd4c7", + "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" + } + ] + }, + { + "seqno": 335, + "wire": "88d60f0d02353056034745546496df697e94038a693f750400894082e099b8d3ca62d1bfd3e3", + "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" + } + ] + }, + { + "seqno": 336, + "wire": "488264027689aa6355e5802ef2edb5ea5f8b1d75d0620d263d4c79a68fe6d80f28bbacde4b4452b6271c71c03d007ed4be7a466aa05e43525424f615721e9fb53079acd615106eb6afa500cada4fdd61002ca8166e32f5c138a62d1bff0f1f9b9d29aee30c10f524b525790d495093d855c87a58acde4b42f31a5f0f0d0130", + "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" + } + ] + }, + { + "seqno": 337, + "wire": "88e46496dc34fd280654d27eea0801128166e32f5c640a62d1bfd9d80f0d847c2e841f6196dc34fd280654d27eea0801128166e32f5c640a62d1bfe8408af2b10649cab0c8931eaf044d4953534088f2b10649cab0e62f0130589aaec3771a4bf4a523f2b0e62c00fa529b5095ac2f71d0690692ff4089f2b511ad51c8324e5f834d96977b05582d43444e", + "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" + } + ] + }, + { + "seqno": 338, + "wire": "88e3e20f0d033533385a839bd9abde", + "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" + } + ] + }, + { + "seqno": 339, + "wire": "88e4e30f0d03333536bede0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fe1d4", + "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" + } + ] + }, + { + "seqno": 340, + "wire": "88e4e30f0d03353339bede", + "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" + } + ] + }, + { + "seqno": 341, + "wire": "88daded46496c361be940054ca3a940bef814002e001700053168dffe2e4d9e50f0d03353435d6bf0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2f", + "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" + } + ] + }, + { + "seqno": 342, + "wire": "88f56196dc34fd280654d27eea0801128166e32f5c65a53168df768dd06258741e54ad9326e61c5c1f7f0fa1bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa5de1b94d5bef7f3f4089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277f0f0d0131f8f7", + "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" + } + ] + }, + { + "seqno": 343, + "wire": "ce7686c58703025c1f5f92497ca589d34d1f6a1271d882a60e1bf0acf70f0d0130c6e60f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fe9dc", + "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" + } + ] + }, + { + "seqno": 344, + "wire": "88eceb0f0d826441c6c4", + "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" + } + ] + }, + { + "seqno": 345, + "wire": "d0e2e6dcc5e9bee0bf0f0d0130ddc60f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2f", + "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" + } + ] + }, + { + "seqno": 346, + "wire": "885f88352398ac74acb37f0f0d840bce001fd36496dd6d5f4a01a5349fba820044a01db8066e002a62d1bfc6f8", + "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" + } + ] + }, + { + "seqno": 347, + "wire": "88588da8eb10649cbf4a54759093d85fdf0f0d023432fb6496dd6d5f4a01b5b2db52c2001b5042b8005c0014c5a37f0f28d6b450008191b75d12ce8dd6d669f0b2b3e565a59f0c61291970ae3ae33b3b8239bed42f9acd6151061b0df4a002b612c6b080165403f7197ae32d298b46ffb5243d2335502e82d9dcd54cb23d21721e9fb52b1a67818fecc57f0796bdae0fe74eac8a5fc1c46a6ae1b54bbc3729c34e4fe7eb7f33842507417f", + "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" + } + ] + }, + { + "seqno": 348, + "wire": "88f2f10f0d03323435ccca0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fefe2", + "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" + } + ] + }, + { + "seqno": 349, + "wire": "887689aa6355e5802ee2ecb75f87352398ac4c697f0f0d0234396c96c361be94036a436cca08010a817ae34ddc644a62d1bff152848fd24a8fce7f0388ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 350, + "wire": "88c1e4d16496d07abe940054ca3a940bef814002e001700053168dff6196dc34fd280654d27eea0801128166e32f5c65b53168df0f0d023433c058b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfea", + "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" + } + ] + }, + { + "seqno": 351, + "wire": "88768586b19272ff6c96e4593e940bea6e2d6a0801128266e320b8cbea62d1bf0f1394fe632c816e35a4001668830b8e352bee36407f3fc40f0d8365913d7f0ab5acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a97f0711a9be1c8353570daa5de1b94e1a727f3fcc2c4", + "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" + } + ] + }, + { + "seqno": 352, + "wire": "88e86196dc34fd280654d27eea0801128166e32f5c65d53168dffdca0f289fbba3f22675de803f6a5634cf031f6a487a466aa05fb9cc42ca6ee55c87a7ef7f00c4acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ed5b54d392fa97b86d52fe0e2a6f87229af742a64e30a9ab86d5376f854e1a7229a61e2a64d3bff958a1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd294da84ad617b8e83483497f064022d317b93e082d8b43316a4fd424216b4ad82a21e435537dc0f0d83784d03", + "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" + } + ] + }, + { + "seqno": 353, + "wire": "88c5c35f8b497ca58e83ee3412c3569f6496dc34fd280654d27eea0801128166e32f5c65d53168df5895a47e561cc5801f4a547588324e5fa52a3ac849ec2ff5c50f0d03333932cc0f28bdbda2fdf821872722ecc1f3f721e919aa808340e82d2590c35c87a7eeb1a67818fb2f9acd615106eb6afa500d29a4fdd410022502cdc65eb8cbaa62d1bf", + "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" + } + ] + }, + { + "seqno": 354, + "wire": "880f28ff09b1288a1861860d19edbb336ffe78a18c1835070f0db7616490d1353523fdc70f9ca8f5bf38a7f0c72bef54f8bf793191acbe098ddc0d43a7f30decd37e51e51d387be62c2ec92e8f3a441a78654ffb6ff7ccfe2083ed4be7a466aa05ec2f7410cbd454fda983cd66b0a88375b57d280656d27eeb08016540b37197ae32ea98b46ffb5358d33c0c7f4088f2b5761c8b48348f89ae46568e61a002583f7f06e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f76035253495886a8eb10649cbff96496df3dbf4a002a651d4a05f740a0017000b800298b46ff5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60e1bf0acf7f5e5f8cb", + "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" + } + ] + }, + { + "seqno": 355, + "wire": "88cb768dd54d464db6154bf79812e05c1f54012a0f28da445dcd07feef6effe770ffc13cd42f6103e06c2e02fbd75670000003086f00207af5f6bff77b07ff3ed4c1e6b3585441be7b7e94504a693f750400baa059b8cbd719754c5a37fda97cf48cd54081af1c645c87a7ed4d634cf0314003782d6386a50b34bb4bbf6496c361be940094d27eea0801128166e32f5c65d53168df6c97dd6d5f4a01a5349fba820044a059b8cbd719754c5a37ff58a6a8eb10649cbf4a54759093d85fa5291f9587316007d2951d64d83a9129eca7e94aec3771a4bf4085aec1cd48ff86a8eb10649cbf0f1393fe5b03ed870377d6109e79615f770e17db73f97b012a7f0bbbacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee854d5c36a9934df52f6ad0a69878a9bb7c3fcff4086f282d9dcb67f85f1e3c32f070f0d0234334088ea52d6b0e83772ff8749a929ed4c016f7f1e88cc52d6b4341bb97fe1", + "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" + } + ] + }, + { + "seqno": 356, + "wire": "88d7d20f0d03313733de0f28eaef046f8238c0d09e6db95f009b71b23ef8637a394723607db0942d36f48cbee2ce38cb407997db03ed84adc8f32d44cb2e39f6a17cd66b0a88370d3f4a0195b49fbac20044a05ab807ae32ea98b46ffb52b1a67818fb5243d2335502e596529126ee5a4a345b6157a8a9cc640130768821e8a0a4498f5041408b20c9395690d614893772ff86a8eb10649cbf408caec1cd48d690d614893772ff86a8eb10649cbfc77f06a7acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725ffe7f", + "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\"" + } + ] + }, + { + "seqno": 357, + "wire": "89e67b8b84842d695b05443c86aa6ff7e3dd0f0d0130e4e1c9", + "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" + } + ] + }, + { + "seqno": 358, + "wire": "88769086b19272b025c4b85f53fae151bcff7f5f961d75d0620d263d4c7441eafb24e3b1054c1c37e159efd0409419085421621ea4d87a161d141fc2d495339e447f95d7ab76ffa53160dff4a6be1bfe94d5af7e4d5a777f409419085421621ea4d87a161d141fc2d3947216c47f99bc7a925a92b6ff5597e94fc5b697b5a5424b22dc8c99fe94f90f0d8208455888a47e561cc5802effe2e9", + "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" + } + ] + }, + { + "seqno": 359, + "wire": "88e56c96c361be94134a65b6a5040036a08571b0dc65953168df0f1393fe652902f9160c6b3328db08da8de23ad03f9febe4f5c45a839bd9ab0f0d023338e4eb", + "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" + } + ] + }, + { + "seqno": 360, + "wire": "88e76c96d07abe941094d444a820044a05bb8db7719714c5a37f0f1392fe5a005c956786b34420dd289b180a007f3fede6f7c6bf0f0d033133356196dc34fd280654d27eea0801128166e32f5c65e53168dfed", + "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" + } + ] + }, + { + "seqno": 361, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03323733c2c00f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c082ebe17da602b07c85798d2fddd46496dc34fd280654d27eea0801128166e32f5c65e53168df", + "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" + } + ] + }, + { + "seqno": 362, + "wire": "88f56196dc34fd280654d27eea0801128166e32f5c682a62d1bf768dd06258741e54ad9326e61c5c1f7f0ea1bdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa5de1b94d5bef7f3f4089f2b567f05b0b22d1fa868776b5f4e0df408cf2b0d15d454addcb620c7abf8712e05db03a277f0f0d01315885aec3771a4b5f92497ca58ae819aafb50938ec415305a99567b", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_24.json b/http/http-client/src/test/resources/hpack-test-case/story_24.json new file mode 100644 index 0000000000..5156550b33 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_24.json @@ -0,0 +1,1253 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264025f95497ca589d34d1f6a1271d882a60320eb3cf36fac1f408721eaa8a4498f57842507417f0f1f9b9d29aee30c78f1e17258334c8a0c84ae7b2660719ed4b08324a863798624f6d5d4b27f6196dc34fd280654d27eea0801128166e32d5c0b8a62d1bf768586b19272ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88c15890aed8e8313e94a47e561cc5802d34007f6c96dc34fd280654d27eea0801128105c03371a6d4c5a37f6196dc34fd280654d27eea0801128105c03371a6d4c5a37f5a839bd9ab7b8b84842d695b05443c86aa6f0f0d84081969afc7408bf2b4b60e92ac7ad263d48f9d868a0fe16c361e95274a6b45c61894f65b4a17258334c8a0c84ae7b26fc46496d07abe94032a5f2914100225020b8066e34da98b46ff", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "88c85891a47e561cc5804dbe20001f4a576c74189f6c96df697e940b8a6a2254100225042b8066e000a62d1bff6196df697e940b8a6a2254100225042b8066e000a62d1bffc4c30f0d83081f7f5f94497ca582211f6a1271d882a60320eb3cf36fac1fc3c96496df3dbf4a05b5349fba820044a085700cdc0014c5a37f", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88cd588ea47e561cc5802dfd295db1d0627f6c96dc34fd280654d27eea0801128166e32cdc6df53168df6196dc34fd280654d27eea0801128166e32cdc6df53168dfc9c80f0d8371969a5f99497ca58e83ee3412c3569fb50938ec41530190759e79b7d60fc8ce6496dc34fd280654d27eea0801128166e32d5c0b4a62d1bf", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88d2c76c96df697e9403ea6a225410022500e5c0b3704f298b46ff6196df697e9403ea6a225410022500e5c0b3704f298b46ffcdcc0f0d8413c00bbfc1cbd16496df3dbf4a01e5349fba820044a01cb8166e09e53168df", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88d56c96d07abe94132a65b6a504003ca099b8072e042a62d1bf5892aed8e8313e94a47e561cc58190b6cb80000152848fd24a8f6196df697e9403ea6a225410022500ddc659b800298b46ffd10f0d83085b075f87497ca58ae819aad76496c361be9403aa6a225410042500ddc659b800298b46ff", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88db588fa47e561cc58197000fa52bb63a0c4f6c96dc34fd280654d27eea0801128115c65cb8db4a62d1bf0f28bf25114859629eb81139c7423ed490f48cd540b92c19a6450642573d937da958d33c0c7da85f359ac2a20dd6d5f4a0195b49fbac165408ae32e5c6da53168dff6196dc34fd280654d27eea0801128115c65cb8db4a62d1bfd7d60f0d83704d37dfd5db6496dc34fd280654d27eea0801128166e32e5c6da53168df", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88dfd46c96df3dbf4a002a693f750400894102e36cdc65d53168df6196df3dbf4a002a693f750400894102e36cdc65d53168dfdad90f0d83700d3bd3d8de6496dc34fd2800a97ca450400894102e36cdc65d53168dff", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88e2d76c96df3dbf4a002a693f750400894102e36cdc0baa62d1bf6196df3dbf4a002a693f750400894102e36cdc0baa62d1bfdddc0f0d8371969ad1dbe16496dc34fd2800a97ca450400894102e36cdc0baa62d1bff", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88e5da6c96df697e9403ea6a225410022500e5c006e36153168dff6196df697e9403ea6a225410022500e5c006e36153168dffe0df0f0d03343733d4dee46496df3dbf4a01e5349fba820044a01cb800dc6c2a62d1bf", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88e8dd6c96df697e9403ea6a225410022500e5c006e36da98b46ff6196df697e9403ea6a225410022500e5c006e36da98b46ffe3e20f0d8413c00bbfd7e1e76496df3dbf4a01e5349fba820044a01cb800dc6db53168df", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88ebd3d2d1d0e30f0d83085b07cfe8ce", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88eb588eaed8e8313e94a47e561cc581c0036c96dc34fd280654d27eea0801128166e32d5c1054c5a37f6196dc34fd280654d27eea0801128166e32d5c1054c5a37fe7e60f0d837dc701efe5eb6496dc34fd280654d27eea0801128166e34fdc1054c5a37f", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88efe46c96df697e9403ea6a225410022500e5c106e32f298b46ff6196df697e9403ea6a225410022500e5c106e32f298b46ffeae90f0d82109bdee8ee6496df3dbf4a01e5349fba820044a01cb820dc65e53168df", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "88f2e76c96df697e9403ea6a225410022500edc102e05e53168dff6196df697e9403ea6a225410022500edc102e05e53168dffedec0f0d8313cdbbe1ebf16496df3dbf4a01e5349fba820044a01db8205c0bca62d1bf", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88f5ea6c96df697e94640a6a2254100225041b8d82e36053168dff6196df697e94640a6a2254100225041b8d82e36053168dfff0ef0f0d830b2fbde4eef46496df3dbf4a09f5349fba820044a08371b05c6c0a62d1bf", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "88f8ed6c96df3dbf4a002a693f750400894106e09cb8d3ca62d1bf6196df3dbf4a002a693f750400894106e09cb8d3ca62d1bff3f20f0d84680cb6cfe7f1f76496dc34fd2800a97ca450400894106e09cb8d3ca62d1bff", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88408721eaa8a4498f57842507417ff16c96c361be940094d27eea080112820dc69cb82754c5a37f6196c361be940094d27eea080112820dc69cb82754c5a37ff7f60f0d83134dbd5f95497ca589d34d1f6a1271d882a60320eb3cf36fac1ff6768586b19272ff6496dd6d5f4a004a5f2914100225041b8d39704ea98b46ff", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88c3f66c96d07abe940b6a6a2254100225042b8076e05d53168dff6196d07abe940b6a6a2254100225042b8076e05d53168dff5a839bd9ab7b8b84842d695b05443c86aa6f0f0d03373237f2408bf2b4b60e92ac7ad263d48f9d868a0fe16c361e95274a6b45c61894f65b4a17258334c8a0c84ae7b26fc46496e4593e940b4a693f75040089410ae01db81754c5a37f", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "885f88352398ac74acb37fca5891aed8e8313e94a47e561cc5804dbe20001f798624f6d5d4b27f6196c361be940094d27eea080112820dc69cb82794c5a37fc9", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88c1cdc0bfcbc9", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88c1cdc0bfbec9", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88c1cdc0bfcbc9", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88cddd6c96dc34fd280654d27eea0801128166e32d5c0bca62d1bf6196dc34fd280654d27eea0801128166e32d5c0baa62d1bfc7c60f0d84081d781fccc5cb6496dc34fd280654d27eea0801128166e34fdc0bca62d1bf", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88d05891a47e561cc5804dbe20001f4a576c74189f6c96dc34fd280654d27eea0801128166e05db8d814c5a37f6196dc34fd280654d27eea0801128166e05db8d814c5a37fcbca0f0d83109a6fd0c9cf6496d07abe94032a5f291410022502cdc0bb71b0298b46ff", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88c8d4c7c66195d07abe941094d444a820044a0857000b810a98b46fd1", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88c9d5c8c76196dc34fd282754d444a820044a045700fdc036a62d1bffd2", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88cad6c9c86196dc34fd282754d444a820044a01db8cb9702253168dffd3", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88cbd7cac96195d07abe941094d444a820044a0857000b811298b46fd4", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88d85890aed8e8313e94a47e561cc5802d34007f6c96dc34fd280654d27eea0801128115c6d9b82654c5a37f6196dc34fd280654d27eea0801128115c6d9b82654c5a37fd3d20f0d836dd6595f92497ca589d34d1f6a1271d882a60b532acf7fd2d86496d07abe94032a5f2914100225022b8db3704ca98b46ff", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88ddc26c96dc34fd280654d27eea0801128105c6deb8db6a62d1bf6196dc34fd280654d27eea0801128105c6deb8db6a62d1bfd7d60f0d830b4f03c1d5db6496d07abe94032a5f2914100225020b8dbd71b6d4c5a37f", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "88e0c56c96dc34fd280654d27eea080112807ee36cdc65e53168df6196dc34fd280654d27eea080112807ee36cdc65e53168dfdad90f0d84081a003fdfd8de6496d07abe94032a5f291410022500fdc6d9b8cbca62d1bf", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "88e3d06c96df697e9403ea6a225410022500e5c006e34ea98b46ff6196df697e9403ea6a225410022500e5c006e34ea98b46ffdddc0f0d8369e7035f94497ca582211f6a1271d882a60320eb3cf36fac1fdce26496df3dbf4a01e5349fba820044a01cb800dc69d53168df", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_25.json b/http/http-client/src/test/resources/hpack-test-case/story_25.json new file mode 100644 index 0000000000..8e692bff5c --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_25.json @@ -0,0 +1,9149 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "48826401768c86b19272ad78fe8e92b015c3a26c95dc34fd28ca9a4fdd410022502cdc0bd704da98b46f0f1f8f9d29aee30c78f1e172c63f4b90f4ff4085b283cc693fa9ada96d9957012f72cfd95700ab379566fa2954576bb5b73e46cbaab386302ae0160b23238ebcf01e6f0f0d01306196dc34fd280654d27eea0801128166e321b8db8a62d1bf", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88c10f28ff1ba8f520a8418f5417a6870e886ecfba4a2ee9d3be16f4efc3d398b65ba2f35e73f4c16e8dfb1bcfd345ba2f35e61d0787261a9dc7d43d34f4235aafe9a746fc1ef9efbb3e9dfcdbd3d36d1a7a6c173f7fb4fed3867d1cb0f4d1b2fe7861c3b28ddaf8e8fc7ad6ff5ef9fb52f9e919aa8172c63f4b90f4fda983cd66b0a88375b57d280656d27eeb08016540b37190dc6dd53168dff6a6b1a678185885aec3771a4b4085aec1cd48ff86a8eb10649cbf5a839bd9ab5f91497ca589d34d1f649c7620a98386fc2b3d0f0d840b410b5fc2", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "886196dc34fd280654d27eea0801128166e321b8dbca62d1bf768586b19272ff6c96c361be940094d27eea0801128005c03b704253168dff0f1394fe5b6de005a588465668923ae96375b189e07f3f52848fd24a8f0f0d83644e3b4087f2b12a291263d5842507417f5f88352398ac74acb37f", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88cb7f0aa6adaa9570165bd25b64a3c11566fbfdd3f29438eaf305b28d90ac1646471d79e6c8e2c0f211870f28faaab31a08c935a6918238ebcf364702c8c0300df95c6dc7a30b92cadbe174a56c4eb8d81a2fff899ad348c11c75e799942164601b6e3ee34571a708e4b28c611902d89d71b0345fff3ed4be7a466aa05cb18fd2e43d3f6a60f359ac2a20dd6d5f4a0195b49fbac20059502cdc64371b794c5a37fda9ac699e063f4003703370d2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a437f40d4bf8388d4d7baf9d4d7ba11a9ab86d53743a0ea64d37d4e1a72297b568534c3c54c9a77a9bb7c2a5fc1a14d7b707f3588caec3771a4bf4a547588324e5c95f87352398ac4c697f0f0d0234326196dc34fd280654d27eea0801128166e321b8dbaa62d1bf", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88c86496dc34fd280654d27eea080112816ee321b8d36a62d1bf6c96dc34fd28171486d9941000ca8205c685704ea98b46ffc1c70f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7f768dd06258741e54ad9326e61c5c1f0f0d023439", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88cb6c96df3dbf4a05e535112a0801128266e36cdc6dd53168df5f87352398ac5754dfca0f1390fe5e005e66491c7a31c8490371d103f9c00f0d83136cbf", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88cd6496d07abe940814be522820044a085702d5c6c0a62d1bff6c96df697e940814cb6d0a0801128005c0bd71b714c5a37fc6ccc2588ba47e561cc581979e7800070f0d82105f", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88d06c96df697e940814cb6d0a0801128005c0bb71b654c5a37fc8ce0f1390fe5e03c5740e8990b652481b8dca1fe7c40f0d821003", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88d16c96e4593e940bca65b6850400894102e32cdc65953168dfc9cfc50f0d830b8267", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88da7f0da6adaaeb9e4a3c11566fbfde8f94ceabb8631c8abb85d12acdf582c8c8e3af3cf360581e42e4bf5890aec3771a4bf4a523f2b0e62c0f38d0017f0ec7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f9cc0f0d023433d5", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88dd7f01a4adaaeb9e4a3c11566fbfdcbf29544f3ad3aab802aaee07160b23238ebcf3822ac0f32c7fc0bfcd0f0d023433cc", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88de7ea4adaaeb9e4a3c11566fbfdcbf29544f3ad3aab802aaee08d60b23238ebcf38e8160790b41c1c0ce0f0d023433cd", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88df7ea3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301dad60b236a365e201c2ac0f21703f6c96df697e9403ea6a225410022504cdc6c171b754c5a37fc2d00f0d83684117588ca47e561cc5804fb4e3c265bf6496df3dbf4a040a6a22541002ca816ee01fb81654c5a37fdb408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88e47f03a5adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301d559bab0591b8d95d24919160790b91ff6c96d07abe940b6a6a225410022502fdc086e05c53168dffc7d50f0d836dc705588ca47e561cc5804fbe16df103f6496df697e940b6a6a22541002ca817ee320b8cbca62d1bfe0c2", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "88e87f02a3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301da560b238e491a7d991b581e42e496c96df3dbf4a002a693f750400894102e32fdc69953168dfcbd90f0d837c2f35588ca47e561cc58190b2f840d35f6496c361be940054d27eea0801654106e05cb801298b46ffe4c6", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88ece66c96df697e94642a651d4a0801128015c6deb8cb4a62d1bf5f90497ca582211f649c7620a98386fc2b3d0f0d83644f0b588ca47e561cc5804cb2cb217dbf6497e4593e94642a65b6850400b2a05ab8dbd719694c5a37ff6196dc34fd280654d27eea0801128166e321b8dbea62d1bfcb7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "88f2ec6c96df3dbf4a01c53716b504008940b971b0dc642a62d1bf5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d836da681588ca47e561cc5804e36cb8eba1f6496c361be94038a6e2d6a08016540b971b0dc640a62d1bfc3d0c2", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88f66c96df3dbf4a042a6a225410022502fdc0b7702fa98b46ffea0f0d836c2d3d588ca47e561cc58190b4dbcebcff6496dc34fd280129a4fdd41002ca8172e01bb80794c5a37fc6d3", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88768c86b19272ad78fe8e92b015c36c96d07abe9413aa6e2d6a080102807ee01db82694c5a37fcb5b842d4b70ddc8f60f0d836dc75f5892aed8e8313e94a47e561cc58190b6cb80003f6497dd6d5f4a0195349fba820059502cdc64371b7d4c5a37ffcbd8", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "88c26c96e4593e94642a6a225410022502fdc0bf71b654c5a37ff20f0d83742d83588ca47e561cc58190b4e3cdb2cf6496dc34fd280129a4fdd41002ca817ae34edc644a62d1bfcedb", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88c55a839bd9ab6c96e4593e94134a6a225410022500ddc6c371a0a98b46ffd30f0d836dc75f588ca47e561cc5819038d34cbc2f6496df3dbf4a09a535112a080165403771b0dc682a62d1bfd2dfd1", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88c96c96df3dbf4a002a693f750400894106e09ab8cbea62d1bf5f88352398ac74acb37f0f0d836dc65c588ca47e561cc58190b4d802f3bf6496dc34fd280129a4fdd41002ca8166e341b8d38a62d1bfd6e3", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88cd6c96df3dbf4a002a693f750400894133700cdc132a62d1bfc10f0d83742ebb588ca47e561cc58190b4f3cd841f6496dd6d5f4a0195349fba8200595000b8205c13ea62d1bfd9e6", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88d06c96df3dbf4a002a693f7504008940bd71a0dc65e53168dfc40f0d8379d00b588ca47e561cc58190b220b4067f6496c361be940054d27eea0801654006e36ddc1094c5a37fdce9", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88d36c96c361be940894d444a820044a05ab827ee32fa98b46ffc70f0d840b2069cf588ca47e561cc5804fb8cbaeb4e76496dc34fd281129a88950400b2a05ab816ae09b53168dffdfec", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88d67f28a7adaaeb9e4a3c11566fbf6aaee0f94d2e32baacde7447a5c559c0b0591c648d96df65d581e42d176c96df697e94640a6a2254100225041b8076e32d298b46fff5cb0f0d84700f81cf588ca47e561cc58190b2e880d3ff6496c361be940054d27eea08016540b771b7ee09d53168df6196dc34fd280654d27eea0801128166e321b8dbca62d1bff1", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88dbd36c96df697e940bca6e2d6a080112800dc082e09f53168dffe20f0d846842037f588ca47e561cc5804eb61742107f6496e4593e940bca6e2d6a0801654006e041704fa98b46ffe7f4e6", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88dedde4dcd60f0d846d965b7fe65892aec3771a4bf4a523f2b0e62c0c85b65c0001dbe8f5", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "886196dc34fd280654d27eea0801128166e322b800a98b46ff6c96df697e940b8a6a225410022502f5c03971b7d4c5a37f5f87352398ac5754df52848fd24a8f768dd06258741e54ad9326e61c5c1f0f0d83136f330f1390fe5e015928de23e38c9206e38cbffcff", + "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\"" + } + ] + }, + { + "seqno": 29, + "wire": "48826402e57f0da4adaaeb9e4a3c11566fbfde8f94ceabb8631c8abb85d08160b23238ebcf8a56560790b21f5886a8eb10649cbf4003703370c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f95f87352398ac4c697f0f0d0130c76401300f28bdd7ba0deb83ed4be7a466aa0a466a972c63f562695c87a7ed4c1e6b3585441badabe94032b693f758400b2a059b8c8ae002a62d1bfed4d634cf0316269f0f1fffda029d29aee30c22cf2bd23354b9631fab134ae43d2c589a7fcda9a6f5327c0e0e883d5f1441ffaffd4517febff5145ffaffd7c4d011c75e799942164601b6e3ee34571a708e4b28c611903f048038da46486186186186186e8b578e565ed976f6275acfdf46abd467fcdacfea09d697a62f7cfb5add82dcb3f96fd6e9347199ceb65bd3f075aa2baf75d17efdf5458551610bdef365ed92cf58737a86fd7371dfd796dd9c68478dd8b9aa2bbabde2e999ed328551612e9df3efbdb1fa40cefc58bd32d61a45ac1af84d0bbe78bd0f6c5eb37b9e571acbba7e6a8b0f87129be0d596ee2e79bf1db7cb2d0ff71e6c593d6fa238e5df689fdcfe6da0cf7f72a2c25237eb509dbb9f321515debd72f8709dfa61b71aa2bbaabcf66c2cfd71b762a2ba3b45de1f793975f39ba666f77667317479437dfdd3cdf04b47554587d8b7bf7bb96671cf10c30c2ab37d566ffc570042d89db810b627ae042d89ff890d0042d89db810b627ae042d89ff8ef035f05a89070df8567be23a6013ce3c077e0f64900596c2fb4fb620b6f03e09340471d79e6c8e059180601bf2b8db8f46172595b7c2e94bf048e0efd0ebc889571a105a63a3d2fc7a5ea0c5a930a105a63a0b62f110745118c9d41f1177b24a600b2d85f69f6c416de0fc5907a2a3", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88c86496d07abe940814be522820044a00571a05c13ca62d1bff6c97df3dbf4a01f532db4282001f502f5c659b8cbea62d1bffc8c7c6588ba47e561cc581979e7800070f0d830b4073", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "88cb6497dd6d5f4a09b5349fba820044a099b8d3971b714c5a37ff6c96d07abe940b2a65b68504003ea08571a66e32ca98b46fc4ca0f138ffe5e005e8c6dbf1b44186e3720bf9fc9c00f0d03333836", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "88cd6c97df3dbf4a01f532db4282001f502f5c659b8d054c5a37ffcccbca0f0d83642db70f1390fe5e015928de23e38c9206e38cbffcff", + "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\"" + } + ] + }, + { + "seqno": 33, + "wire": "88f07f09a4adaaeb9e4a3c11566fbfde8f94ceabb8631c8abb85d0b6b059191c75e7d96c2b03c8443fc8c7f70f0d83699103cfc50f28ddc7be00b2d85f69f6c416de02a01042d89f540d09e75e75c540e09c0b2d36a819085b13ca81a13ce3c26550382700d34caa064216c4eaa0684f38f002a81c10197c0f7da97cf48cd54148cd52e58c7eac4d2b90f4fda9ac699e062c4d3fe9", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "88cf6496d07abe94138a693f750400894006e01db8d3ea62d1bf6c96c361be94036a6a225410022502f5c69eb81714c5a37fcfcecdc40f0d847c4dbad7", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88d16497dd6d5f4a09b5349fba820044a099b8d3971b6d4c5a37ff6c96df3dbf4a09f5340ec5040089410ae32e5c0014c5a37fd1d00f138ffe40d3c3236094921240dc700cff3fcfc60f0d8465b089ef", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88f57f03a3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301da560b2cca02b7296422c0f21685f6c96df697e9413ea693f7504008540bf702fdc0baa62d1bfcd5f86497ca582211f0f0d03353435588ca47e561cc5819036e32c81bf6496e4593e94132a6a22541002ca8076e081704e298b46ffd8408721eaa8a4498f5788ea52d6b0e83772fff37b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "886196dc34fd280654d27eea0801128166e322b801298b46ff6496df697e940bca5f2914100225000b826ee01e53168dff6c96c361be940094d27eea0801128005c139700253168dff768c86b19272ad78fe8e92b015c354012ad2f40f0d84109a13df", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "88c26496df697e940bca5f2914100225000b826ee01b53168dff6c96c361be940094d27eea0801128005c13d704f298b46ffc1c0d4f60f0d8465979f6f", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88c46496d07abe940baa5f291410022502e5c03f71b6d4c5a37ff1c2c1d5f70f0d8465e75c0f", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88c56496d07abe940baa5f291410022502ddc002e09a53168dff6c96c361be940894d444a820044a05ab827ae34e298b46ffc4c3d7f90f0d84700075ef", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88c47f0fa5adaaeb9e4a3c11566fbf6aaee0f94aa279d6c122aee1132b0591c7236fbe408560790b8eff6c96d07abe9413ea6a2254100225040b816ae040a62d1bffde5f88352398ac74acb37f0f0d84744e05ff588ca47e561cc58190b2f09f65ef6496c361be940054d27eea08016540bf7000b8dbea62d1bfe9ce", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "88c97f03a7adaaeb9e4a3c11566fbf6aaee0f94d2e32baacde7447a5c559c0b059190401c71b61581e42d13f6c96c361be940094d27eea0801128172e362b8db4a62d1bfe3c20f0d8471f7800f588ca47e561cc58190b4e05c65bf6496dc34fd280129a4fdd41002ca8172e362b8cb8a62d1bfedd2", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "88cd0f28ff1ba8f520a8418f5417a6870e886ecfba4a2ee9d3be16f4efc3d398b65ba2f35e73f4c16e8dfb1bcfd345ba2f35e61d0787261a9dc7d43d34f4235aafe9a746fc1ef9efbb3e9dfcdbd3d36d1a7a6c173f7fb4fed3867d1cb0f4d1b2fe7861c3b28ddaf8e8fc7ad6ff5ef9fb52f9e919aa8172c63f4b90f4fda983cd66b0a88375b57d280656d27eeb08016540b37190dc6dd53168dff6a6b1a678185885aec3771a4b4085aec1cd48ff86a8eb10649cbf5a839bd9ab5f89352398ac7958c43d5f0f0d83085b076196dc34fd280654d27eea0801128166e322b80714c5a37f6c96d07abe941094d444a820044a099b806ae044a62d1bff", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "886196dc34fd280654d27eea0801128166e322b80754c5a37f6496dc34fd280654d27eea080112816ee321b8d36a62d1bf6c96dc34fd28171486d9941000ca8205c685704ea98b46ffedf3f2e90f0d0234390f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7f", + "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\"" + } + ] + }, + { + "seqno": 45, + "wire": "88c0e26c96df3dbf4a05e535112a0801128266e36cdc6dd53168dff5f40f1390fe5e005e66491c7a31c8490371d103f9f3ea0f0d83136cbf", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "88c16c96df3dbf4a320532db4282001f504cdc683704fa98b46feff5f40f0d0235330f1390fe5e015928de23e38c9206e38cbffcff6496dc34fd280654d27eea080112816ee05ab82794c5a37f", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88c36496d07abe94138a693f75040089403771b72e34153168df6c97df3dbf4a320532db4282001f504cdc683719654c5a37fff2f8f7ee0f0d0235330f1391fe5e046d4b234d3928424186e3ceb9fcff", + "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\"" + } + ] + }, + { + "seqno": 48, + "wire": "88db0f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645700ea98b46ffb5358d33c0c7fcbcac95f91497ca589d34d1f649c7620a98386fc2b3d0f0d84134db8efc6", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "88c66496dd6d5f4a05c52f948a0801128176e361b8d3ea62d1bf6c96dd6d5f4a09c5309635040089403b71a05c0014c5a37fdeddf1d50f0d830bee3d", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "88c86496dd6d5f4a01a5349fba820044a05cb8cbb71b0298b46f6c96df697e9403aa65b68504003ea081702f5c684a62d1bff752848fd24a8f768dd06258741e54ad9326e61c5c1ff50f0d033631330f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7f", + "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\"" + } + ] + }, + { + "seqno": 51, + "wire": "88cc6497dd6d5f4a09b5349fba820044a099b8d3971b754c5a37ff6c96df3dbf4a099521b66504003aa08171a05c1094c5a37f5f87352398ac4c697fc20f1390fe5e005e66491c7a31c8490371d103f9c1f80f0d82109f", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "88cfc96c96df3dbf4a01a535112a0800754106e34d5c65c53168dfbfc3c2f90f0d830bcf3b0f138ffe4118e4688124ae11e0dc71e17f3f", + "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\"" + } + ] + }, + { + "seqno": 53, + "wire": "88d0cfcebfc30f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7fc20f0d023439", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "88d06496d07abe940bea693f75040089410ae0817191298b46ff6c96dc34fd28265486bb1410021500fdc65db8d014c5a37fe8e7588ba47e561cc581979e780007e00f0d8365f65c", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "88d36496df3dbf4a05952f948a080112817ae34cdc6da53168df6c96df3dbf4a01f53716b504008140bb7190dc640a62d1bfebeac0e20f0d83680dbf", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88d56496df3dbf4a05952f948a080112817ae09ab8cbca62d1bf6c96df3dbf4a01f53716b504008140bb702ddc03ca62d1bfedecc2e40f0d836997dd", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88eddb6c96df3dbf4a05f5328ea50400894006e09cb801298b46ff5f90497ca582211f649c7620a98386fc2b3d0f0d840804d3df588ca47e561cc5804213e07997ff6496c361be940bea65b6850400b2a059b8272e01c53168dfdbf6f5", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88f1df6c96df3dbf4a040a693f7504008540b3704edc682a62d1bfc10f0d830bafb5588ca47e561cc5802e09e702db9f6496dc34fd2810a9a07e941002ca800dc13d700ca98b46ffdef9f8", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88f46c96dc34fd2817d4d03f4a0801128166e081702253168dffec0f0d8310190f588ba47e561cc581a65b782f036496d07abe94134a5f2914100225000b807ae09d53168dffe1408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "88f86c96e4593e94642a6a225410022502d5c035702ca98b46fff00f0d83132fb5588ca47e561cc58190b6cb2fb6d76496dd6d5f4a0195349fba8200595022b8dbd700153168dfe5c1", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88768c86b19272ad78fe8e92b015c36c96df3dbf4a01a535112a0801128166e34cdc6c0a62d1bff40f0d8365c781588ca47e561cc58190b6c89e135f6496dd6d5f4a0195349fba8200595022b8cbf702153168dfe9c5", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88c16c96dc34fd281714cb6d4a080112806ae099b8dbaa62d1bff70f0d83644e33588ca47e561cc580200be17dc73f6496c361be940054d03b141002ca8115c65eb81654c5a37fecc8", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88c46c96df697e94034a6e2d6a0801128166e34e5c032a62d1bffa0f0d83134e3f588ca47e561cc5804e01c75a7c5f6496dd6d5f4a002a6e2d6a080165403971905c0bea62d1bfefcb", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88c7f36c96dc34fd281754be522820042a05db816ae34d298b46ff5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d8313620f588ca47e561cc5802fb4fb8e059f6496d07abe940baa65b6a50400b2a01bb816ee34053168dff3cf7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88ccf86c96df3dbf4a05b52f948a08010a8005c65bb811298b46ffda0f0d837c2cb3588ca47e561cc5802f89c65e03ff6496c361be940b4a65b6a50400b2a0457196ee32e298b46ff7d3c1", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88cf6c96d07abe9413ea6a225410022502d5c086e36ca98b46ff5f88352398ac74acb37f0f0d8365d703588ca47e561cc58190b6cb4d09af6496dd6d5f4a0195349fba820059502cdc03771b0a98b46f6196dc34fd280654d27eea0801128166e322b80754c5a37fd8", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88d46c96dd6d5f4a09953716b50400894002e05cb811298b46ffc20f0d8313edb9588ca47e561cc5804eb6269e6dff6496e4593e940bca6e2d6a0801654033702fdc69c53168dfc1db", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88d76c96d07abe9413ea6a225410022502d5c0b3700f298b46ffc50f0d83109973588ca47e561cc58190840db8d07f6496df697e9413ea6a22541002ca8166e36fdc13ca62d1bfc4de", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88da6c96d07abe9403aa681fa504008940337196ae05a53168dfc80f0d830b6007588ba47e561cc581a71b740d0b6496df3dbf4a09d52f948a080112810dc03f704fa98b46ffc7e1", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "88dd6c96e4593e940baa6a2254100225041b8d39700e298b46ffcb0f0d8313627b588ca47e561cc5804f38fbadb8ff6496df697e940054d444a820059502edc03571b714c5a37fcae4", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "88e06c96df697e940094d444a820044a083704edc134a62d1bffce0f0d830bec83588ca47e561cc5804f3c1134fbdf6496df3dbf4a019535112a0801654006e001704da98b46ffcde7", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "88e36c96dc34fd282029a8895040089400ae36edc13ca62d1bffd10f0d830ba217588ca47e561cc581903cf3ed01cf6496dd6d5f4a09d535112a0801654006e36ddc65953168dfd0ea", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "88e66c96df697e940baa65b68504008940b571905c0b2a62d1bfd40f0d8313ee07588ca47e561cc5802e34c85c087f6496dd6d5f4a044a681fa50400b2a05db8d8ae05e53168dfd3ed", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88e96c96e4593e94134a6a225410022502d5c0b5700d298b46ffd70f0d83105c07588ca47e561cc581903ed36113ff6496dd6d5f4a09d535112a08016540bb704d5c0b8a62d1bfd6f0", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "88ec6c96df3dbf4a01a535112a080112816ae04371a654c5a37fda0f0d8313cd07588ca47e561cc5819008410baf7f6496dc34fd2817d4d444a820059500f5c0bd704da98b46ffd9f3", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "88ef6c96d07abe9403aa681fa504008940b371b7ee36fa98b46fdd0f0d830b6d07588ba47e561cc581d136fb2c8b6496dc34fd282714ca3a941002ca816ae00171b7d4c5a37fdcf6", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "88f26c96e4593e94038a65b6a504008940b5700ddc0b4a62d1bfe00f0d831044cf588ca47e561cc5802265969b69ef6496df697e94138a681d8a080165403b71a76e36da98b46fdff9", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "88f56c96df3dbf4a01a535112a080112816ae083702f298b46ffe30f0d03393437588ca47e561cc5804e85971c65cf6496c361be940b2a6e2d6a08016540b7704fdc132a62d1bfe2408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88f96c96df3dbf4a01a535112a080112816ae34ddc0b6a62d1bfe70f0d830bcd39588ca47e561cc5804fbc1640107f6496d07abe940b4a6a22541002ca816ae36ddc65d53168dfe6c1", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "88768c86b19272ad78fe8e92b015c36c96dc34fd282754d444a820044a05ab8176e34153168dffeb0f0d83105c73588ca47e561cc5819036071a71cf6496df697e941094d444a820059502ddc659b81694c5a37f6196dc34fd280654d27eea0801128166e322b80794c5a37fc6", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88c26c96df3dbf4a01a535112a0801128166e34f5c6dd53168dfef0f0d8365f71a588ca47e561cc5819085c0b6ebff6496e4593e94640a6a22541002ca806ee321b8d3aa62d1bfc1c9", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88c56c96df3dbf4a01a535112a0801128166e34cdc644a62d1bff20f0d8369c6d9588ca47e561cc5819036db8e845f6496e4593e94132a6a22541002ca806ee320b8d014c5a37fc4cc", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "88c85a839bd9ab6c96df697e940854dc5ad410022502f5c68571b0a98b46ff5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d84642d3ae7588ca47e561cc5804e3eeb6d34d76496e4593e940854dc5ad41002ca817ae342b8d854c5a37ff6d17b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88cec36c96dc34fd281754be522820042a05db816ae34da98b46ffc20f0d840842f07fbf588ca47e561cc5802fb4fb8d89ef6496d07abe940baa65b6a50400b2a01bb816ae05b53168dffad5", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88d16c96df3dbf4a01a535112a080112816ae05fb8cb2a62d1bf5f88352398ac74acb37f0f0d836db781588ca47e561cc58190b6cb6e381f6496dd6d5f4a0195349fba820059502cdc139704f298b46f6196dc34fd280654d27eea0801128166e322b80754c5a37fda", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88d64085b283cc693fa4adaaeb9e4a3c11566fbfde8f94ceabb8631c8abb85d0b4b059191c75e1caf0160790b41f5886a8eb10649cbf4003703370c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f9cc0f0d03393033d56401300f28ff1ec7be00b2d85f69f6c416de02a01042d89f540d09e75e75c540e09c0b2d36a819085b13ca81a13ce3c26550382700d34caa064216c4eaa0684f38f002a81c10197c0f2a008596c2fb4fb62744e3ea804fbc1540d2c1540e015032fbc0540d2c1540e015032fbafaa06960aa0700a81971e795034b0550380540c89b6d5034b0550380fb52f9e919aa82919aa5cb18fd589a5721e9fb5358d33c0c589a7fcf", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "886196dc34fd280654d27eea0801128166e322b807d4c5a37f6496d07abe940baa5f291410022502e5c6817197d4c5a37f6c96e4593e940814cb6d4a08007d40b971b7ae36e298b46f5f87352398ac5754df52848fd24a8f0f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7f768dd06258741e54ad9326e61c5c1f0f0d83085c0f588ba47e561cc581979e780007", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88c46496e4593e9413ca693f750400894037700e5c132a62d1bf6c96dc34fd281714d03f4a08007d4006e05cb800298b46ff5f87352398ac4c697fc3c2c10f0d83085e070f1390fe40d3ce3524a46646c8f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 89, + "wire": "880f0d023636be6c96c361be940bea65b6a504003ea05db8d82e32253168dfc40f138ffe40e351bce81c94247c371c785fcfc3c86496dc34fd282754d444a820044a01eb827ee34053168dffea", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88c96496df3dbf4a05952f948a080112817ee32ddc69c53168df6c96df3dbf4a05d5340ec50400854106e01fb800a98b46ffc8c7c6c50f0d840b2e859f0f138ffe4118e4688124ae11e0dc71e17f3f", + "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\"" + } + ] + }, + { + "seqno": 91, + "wire": "88e8dd6c96df697e940b4a612c6a080112807ae00171a754c5a37fdc0f0d846d903ef7588ca47e561cc5804d36e01f08bf6496e4593e940b4a436cca0801654102e0017197d4c5a37fd3efdb", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "88ebe06c96dd6d5f4a09e535112a0801128266e34e5c0b6a62d1bfdf0f0d8413a203ff588ca47e561cc5819081b69a69ef6496d07abe9413ca6a22541002ca8266e34e5c0b6a62d1bfd6f2de", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "887689bf7b3e65a193777b3f5f87497ca589d34d1f0f0d03333937e56196dc34fd280654d27eea0801128166e322b810298b46ff", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88be6496dc34fd2816d4be522820044a01fb8db9704f298b46ff6c96dc34fd28171486d9941000ca8205c685704ea98b46ffcdd2d1d00f0d023439", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "88c06c96d07abe9403ca681d8a080102817ee322b8cb6a62d1bfced3d20f0d03313436", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88f46c96d07abe941094d444a820044a0817197ae36da98b46ffe00f0d830be17b588ca47e561cc5819001b0b2107f6496df3dbf4a05d535112a080165403f700edc0baa62d1bfdffb", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88d16c96df3dbf4a002a693f7504008940bd7000b8cb2a62d1bf6196c361be940094d27eea080112817ae045700ea98b46ff6496dc34fd280654d27eea080112817ae045700ea98b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d84138f041f408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f558471f700cf5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88768c86b19272ad78fe8e92b015c36c96d07abe941094d444a820044a099b806ae044a62d1bff5f89352398ac7958c43d5f0f0d83085b076196dc34fd280654d27eea0801128166e322b810a98b46ff", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "886196dc34fd280654d27eea0801128166e322b811298b46ff6496d07abe94138a693f750400894002e09fb82694c5a37f6c96c361be940bca681d8a08006d4133700cdc6da53168dfe0e5e4e30f0d8213800f1390fe40d3ce3524a46646c8f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 100, + "wire": "88c06496df697e940854be522820044a08171a6ee34f298b46ff6c96c361be9413aa436cca0801028005c10ae36ca98b46ffe2e70f1390fe5e005e66491c7a31c8490371d103f9e6e50f0d03333636", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88c26c96c361be940bca681d8a08006d4133700d5c65f53168dfe3e8e70f0d820ba20f1390fe5e015928de23e38c9206e38cbffcff6496df697e94038a693f7504008940b971b76e09e53168df", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "88c80f28bba2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645702253168dff6a6b1a678185885aec3771a4b4085aec1cd48ff86a8eb10649cbf5a839bd9ab5f91497ca589d34d1f649c7620a98386fc2b3d0f0d847c0f89bfc9cb", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "88c86496df3dbf4a05952f948a080112817ee00171a0298b46ff6c96df3dbf4a01f53716b504008140bb7190dc640a62d1bfce54012aeefc0f0d84085b035f408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "88ccc1c0d0bfef5f88352398ac74acb37f0f0d84085b035fbf", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "88d16c96df3dbf4a05e535112a0801128215c69cb8d3ea62d1bfbf0f0d8365f705588ca47e561cc5804f81c7997def6496dd6d5f4a01c535112a0801654002e01bb8c814c5a37fd0c2", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "88d46c96e4593e94642a6a225410022502edc6d9b8d814c5a37fc20f0d8369c741588ca47e561cc5819089d700dbdf6496df3dbf4a321535112a08016540b3702fdc6c0a62d1bfd3c5", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "88d76c96df3dbf4a042a6a2254100225001b8d8ae36da98b46ffc50f0d836dc75f588ca47e561cc5804f3ccb40685f6496df3dbf4a019535112a080165403971b7ee32d298b46fd6c8", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88da6c96e4593e94136a65b6850400894102e360b8d054c5a37fc80f0d8365f13f588ca47e561cc5802ebeebcf81af6497df3dbf4a3205340fd2820059502ddc681719714c5a37ffd9cb", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88dd6c96d07abe94038a436cca0801128072e059b82794c5a37fcb0f0d83134eb3588ca47e561cc58042032e3aebdf6496df697e940b8a65b6850400b2a05ab8d86e36053168dfdcce", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88e06c96d07abe9413aa6e2d6a080102807ee01db82694c5a37f5f90497ca582211f649c7620a98386fc2b3d5b842d4b70ddd60f0d83702e8b7b8b84842d695b05443c86aa6f5892aec3771a4bf4a523f2b0e62c0c85b65c00016496dd6d5f4a0195349fba820059502cdc645702253168dfe2d4", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "88e6d96c96c361be940b8a681d8a0801128005c681704ca98b46ff5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d846c4fb60f588ca47e561cc5804e882279f17f6496dc34fd281694dc5ad41002ca8115c681704d298b46ffe6d8c4", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "88ea6c96dd6d5f4a09d5340fd2820044a045704e5c0bca62d1bfd80f0d83702e33588ca47e561cc5802ebed05b65bf6497df3dbf4a3205340fd2820059500ddc0bb71a754c5a37ffe9db", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88ed6c96d07abe940b2a436cca0801128072e362b8cb6a62d1bfdb0f0d8369b139588ca47e561cc5804d34fbcf881f6496e4593e940b4a436cca080165400ae34edc65953168df6196dc34fd280654d27eea0801128166e322b81654c5a37fdf", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88f1cec7cccbe40f0d8469e7c4d75892aed8e8313e94a47e561cc58190b6cb80003fcaeee0", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "886196dc34fd280654d27eea0801128166e322b81694c5a37f6496d07abe940baa5f291410022502e5c6817197d4c5a37f6c96e4593e940bea6a2254100215000b8d3d702fa98b46ff5f87352398ac5754df52848fd24a8f0f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7f768dd06258741e54ad9326e61c5c1f0f0d03323735588ba47e561cc581979e780007", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "880f0d83085a6fc16c96df697e940b6a612c6a08010a8176e32e5c0854c5a37fc10f1391fe5e046ec8391b65c24848c371e6dafe7fc0c56497dd6d5f4a09b5349fba820044a099b8d3971b6d4c5a37ffe9c0", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "88c66496dd6d5f4a01a5349fba820044a01ab8dbf704da98b46f6c96e4593e940094c258d410021502fdc699b81754c5a37f5f87352398ac4c697fc50f1390fe5e005e66491c7a31c8490371d103f9c4c30f0d8365b69c", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88c96496df3dbf4a09d53716b50400894133702ddc680a62d1bf6c96c361be941054ca3a94100215040b8d8ae36253168dffc0c7c6c50f0d837196850f1390fe4031baf0a31c91be48c371c785fcffee", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "88cb6c96df3dbf4a01f53716b5040081403371a05c1014c5a37fc9c8c70f0d84081e7dcf0f1390fe5e015928de23e38c9206e38cbffcff6496dd6d5f4a05c52f948a080112806ee34d5c65e53168dfc7", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "88cd6497dd6d5f4a09b5349fba820044a099b8d3971b754c5a37ff6c96c361be941094cb6d4a0801128215c03f704153168dffcccbcac90f0d846df742ff0f1390fe40d3ce3524a46646c8f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 121, + "wire": "88cfbecccbca0f0d846df742ffbfc9", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "88768c86b19272ad78fe8e92b015c34085b283cc693faaadaa9570165bd25b64a3c11566fbfdd3f29438eaee0a46d566f2ace07560b23238ebc47da65607908daf588caec3771a4bf4a547588324e5fb5f87497ca58e883d5f798624f6d5d4b27fd4", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "88c20f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645702e298b46ffb5358d33c0c7f5885aec3771a4b4085aec1cd48ff86a8eb10649cbf5a839bd9ab5f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e0f0d84780069cf6196dc34fd280654d27eea0801128166e322b816d4c5a37f6c96d07abe941094d444a820044a099b806ae044a62d1bff40884d83a903224c7abfcab7aaf67fb700ec7ffdfffa8fada4a64c922984d5486aa6d761e4b489eed7d6da0f364914adaae937855c0744c6faace1b7aaf62a2bae01d8d57702ae010b059191c75e24627560798ddf", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "886196dc34fd280654d27eea0801128166e322b81714c5a37f6496d07abe940baa5f291410022502cdc69cb8db4a62d1bf6c96df3dbf4a01f53716b504008140bb7190dc640a62d1bfcc54012ad95f88352398ac74acb37f0f0d03373339408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "88c36496df3dbf4a084a693f7504008940b5702fdc682a62d1bf6c96dc34fd28265486bb1410021500fdc65db8d014c5a37fd1c2ddc10f0d830b8d3fc0", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "88c56496dd6d5f4a01a5349fba820044a01cb8105c13aa62d1bf6c96c361be940bca681d8a08006d41337001b80694c5a37fdae1e0df0f0d033133340f138ffe40ebcd89b214442361b8dbce7f3f", + "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\"" + } + ] + }, + { + "seqno": 127, + "wire": "88c76496c361be940b4a5f291410022500ddc03d702ca98b46ff6c96c361be941054d444a82001b502f5c69db8d014c5a37fdce30f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7fe20f0d821321e1", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "88c96496dd6d5f4a01f52f948a0801128072e362b81794c5a37f6c96df697e94038a6e2d6a08006d40bf71976e34e298b46fdee50f1390fe5e005e66491c7a31c8490371d103f9e4e30f0d03363433", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "88cb6496c361be94138a6a225410022500d5c699b8c854c5a37f6c96df3dbf4a01c535112a08006d4106e09fb81694c5a37fe0e7e6e50f0d033336390f1390fe4031baf0a31c91be48c371c785fcffc8", + "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" + } + ] + }, + { + "seqno": 130, + "wire": "880f0d03313939e06c96c361be941054d444a82001b502f5c69db8d094c5a37fe80f1391fe5e046ec8391b65c24848c371e6dafe7fe7cee4c9e6", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "88ce6c96e4593e94034a681d8a08007d40337022b8c814c5a37feae9e80f0d83132f3d0f1390fe5e015928de23e38c9206e38cbffcffdee7", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88cf6496d07abe940bea693f75040089410ae08171a714c5a37fcedce8cc0f0d830ba167", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "88d06496dd6d5f4a042a693f75040089403971a05c1054c5a37f6c96df3dbf4a01f53716b504008140bb71905c65e53168dfdecfeace0f0d830b2f3fcd", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "88d26496d07abe94138a693f7504008940357190dc684a62d1bf6c96c361be940bca681d8a08006d4133700d5c65a53168dfe7ee0f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7fed0f0d820b41ec", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "88d46497dd6d5f4a09b5349fba820044a099b8d3971b714c5a37ff6c96c361be940bca681d8a08006d4133700ddc0854c5a37fe9f0efee0f0d033133360f138ffe5e00e47a32ca51108d86e3c56bf9d1", + "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" + } + ] + }, + { + "seqno": 136, + "wire": "88d66496df3dbf4a09f5349fba820044a05cb8cbf704153168df6c96df697e94009486d99410021500edc6dbb807d4c5a37fe4f0d40f0d8371c6c3", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "88d86496df3dbf4a01c52f948a080112807ee342b810a98b46ff6c96d07abe9413ca681d8a08010a816ae36ddc6df53168dfe6d7f2d60f0d840b2f09bfd5", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "886196dc34fd280654d27eea0801128166e322b820a98b46ff6c96dc34fd28171486d9941000ca8205c685704da98b46ffeff6f50f0d023439eaf4", + "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" + } + ] + }, + { + "seqno": 139, + "wire": "88e80f28baa2d275f4fc017db7de7c1f77cf48cd540b9631fa5c87a7ef079acd615106f9edfa50025b49fbac2005d502cdc645704153168dff7ac699e0614fe3e2e15f91497ca589d34d1f649c7620a98386fc2b3d0f0d84780069cfc0dfde7f29a44b96d04afa762747d5670dbd55700191d14aa8ae844ab808d60b23238ebc503e5581e4805b842d4b70dde7", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "88c26496dd6d5f4a05e5349fba820044a085704f5c034a62d1bf6c96df3dbf4a01a535112a0800754106e34d5c65f53168dff452848fd24a8f768dd06258741e54ad9326e61c5c1f588ba47e561cc581979e7800070f0d83642ebf0f138ffe40ebcd89b214442361b8dbce7f3f", + "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\"" + } + ] + }, + { + "seqno": 141, + "wire": "88c76c96c361be9413aa436cca0801028005c10ae34f298b46fff8c1c00f0d033339316496dc34fd280654d27eea080112816ee059b821298b46ffc0", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "88c9ce5f87352398ac4c697fc3c20f0d03313336", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "88ca6c96df3dbf4a01c53716b504003aa0017021b8d3aa62d1bfbfc4c30f0d03353432", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "88cb6497dd6d5f4a09b5349fba820044a099b8d3971b6d4c5a37ff6c96df3dbf4a01c532db4282001c5000b8076e000a62d1bfc1c60f138ffe403185b08df00c0470371b28bf9fc5c40f0d023433", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "886196dc34fd280654d27eea0801128166e322b821298b46ff6c96df697e94134a681fa5040085410ae32cdc682a62d1bfc3c8c70f0d830b2d87c4c6", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "88cf6c96df3dbf4a01c53716b504003aa0017041b8c854c5a37fc4c90f1390fe5e04ae8c124a18e5011d0dc6e30ff3c80f0d8371979c", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "88768c86b19272ad78fe8e92b015c3f36c96df3dbf4a09b535112a0801128266e321b8d3aa62d1bf5f90497ca582211f649c7620a98386fc2b3d0f0d83644eb9588ca47e561cc581903afb4cb8e76496c361be94136a6a22541002ca8266e321b8d3aa62d1bfd5ed7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88c3f8c2c10f0d03363638c0bfd6eebe", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "88c3f86c96dc34fd281694cb6d0a0801128005c6c171a754c5a37fc20f0d023434588ca47e561cc58041782cb6073f6496dd6d5f4a05a532db428200595000b8d82e34ea98b46fd9f1c1", + "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" + } + ] + }, + { + "seqno": 150, + "wire": "88d9df6c96df697e940094c258d410020502fdc69ab81694c5a37fced3d2d10f0d840b2f05df", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "88c76c96d07abe9413aa6e2d6a080102807ee01db82694c5a37fc65b842216bdfb5a839bd9ab0f0d83702e8bc55892aec3771a4bf4a523f2b0e62c0c85b65c00016496dd6d5f4a0195349fba820059502cdc645704153168dfdff7", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "88ccc06c96c361be940094d27eea0801128066e09eb8c814c5a37fcb0f0d8371c703588ca47e561cc58190b4165971ff6496dc34fd280129a4fdd41002ca8066e09eb8c814c5a37fe2408721eaa8a4498f5788ea52d6b0e83772ffcb", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "88d0c46c96c361be94038a65b6850400894006e01eb8d34a62d1bfcf0f0d03333531cc588ca47e561cc58041089965d7bf6496dc34fd280714cb6d0a0801654006e01eb8cbea62d1bfe6c1", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "88d36c96d07abe941094d444a820044a019b8076e32153168dff5f88352398ac74acb37f0f0d8369b6d9588ca47e561cc5804fbce38dbee76496df697e940b6a6a22541002ca806ee34f5c6dd53168dfeac5", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "88d76c96dc34fd282129b8b5a820044a05fb8d86e32f298b46ffc10f0d8369c7da588ca47e561cc5804d32ebad805f6496d07abe94089486d9941002ca8176e01ab80654c5a37fedc8", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "88da6c96df697e94640a6a2254100225041b8d3d702da98b46ffc40f0d836d903b588ca47e561cc58190b4fbce819f6496dd6d5f4a0195349fba820059500cdc082e34d298b46ff0cb", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "88ddd16c96df3dbf4a09b535112a0801128266e322b806d4c5a37fdc0f0d8364016b588ca47e561cc581903afb4cb4cf6496c361be94136a6a22541002ca8266e321b82694c5a37ff3cedb", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "88e36496df697e940bca5f291410022502cdc645704253168dff6c96e4593e94642a6a225410022502edc6d9b8d054c5a37fe254012aedcc0f0d840b6fbc1fd1", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "88e6f16c96c361be94136a65b6a50400814006e09eb82794c5a37f5f87352398ac5754dff1f0ef0f0d033537380f138ffe40471e7a371b0b448c371b79cfe7", + "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\"" + } + ] + }, + { + "seqno": 160, + "wire": "88e5db5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf5b84ad2b5ddbe2db0f0d837dc79e5892aed8e8313e94a47e561cc58190b6cb80003fda6196dc34fd280654d27eea0801128166e322b820a98b46ffd7", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "88ec6c96df697e941014dc5ad410021504cdc6dfb8d3aa62d1bff1f6f50f0d830baf030f1390fe5e015928de23e38c9206e38cbffcff6496d07abe94138a693f750400894002e019b8d054c5a37ff5", + "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" + } + ] + }, + { + "seqno": 162, + "wire": "88eb4085b283cc693fa3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301dad60b2fbed35295a7e3581e42eb96c96df3dbf4a099521b66504008940bb704d5c644a62d1bf4003703370c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f95f86497ca582211f0f0d8379d10b588ca47e561cc5804e32fbed3ad76496df3dbf4a01b53716b50400b2a00571a66e32e298b46ff4df", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "88f46c96e4593e940894ca3a94100215040b8276e01f53168dffcb52848fd24a8f768dd06258741e54ad9326e61c5c1f0f0d033334326496d07abe94138a693f7504008940b97196ee05f53168df588ba47e561cc581979e780007", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88f96497dd6d5f4a09b5349fba820044a099b8d3971b6d4c5a37ff6c96e4593e940bea6a2254100215001b8176e34ea98b46ffd1c3c2c00f0d8371c6830f1390fe5e00e513e57e523d21081b8f15afe7e6", + "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" + } + ] + }, + { + "seqno": 165, + "wire": "88f86c96e4593e940854cb6d0a080112817ae019b8cbaa62d1bfe20f0d8313ad8b588ca47e561cc5802d380780077f6496dd6d5f4a082a435d8a08016540b7702fdc03ea62d1bf6196dc34fd280654d27eea0801128166e322b821298b46ffea", + "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" + } + ] + }, + { + "seqno": 166, + "wire": "88be6c96df697e9403aa65b68504003ea081702f5c684a62d1bf5f87352398ac4c697fc9c80f0d03363133c7c60f138ffe40cc820cad025948f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 167, + "wire": "88768c86b19272ad78fe8e92b015c3f36c96df3dbf4a044a65b685040089410ae34d5c13ca62d1bfd80f0d03353531588ca47e561cc58041742fb6273f6496c361be940894cb6d0a080165410ae34d5c13ca62d1bfc4f07b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 168, + "wire": "88c56496d07abe940baa5f2914100225040b8cbf719694c5a37f6c96df697e941014dc5ad4100215002b807ae080a62d1bffded00f1390fe5e005e66491c7a31c8490371d103f9cfcd0f0d840bae3acf", + "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" + } + ] + }, + { + "seqno": 169, + "wire": "88c47f18a64b96d04afa762747d5670dbd55700191d14aa8aeb4ab80666582c8c8e3af15a944b03c840d7f0f28fca8f520a8418f5417a686fe7861c3b28ddaedd1b2fe686f5dfdff7e5ba79fbe6ceac5c01cfdcde740b078e7bf8d1a69d0d7edffde9aafec17ed3fb4eac5cfdf3e946bb3cdbb7eef9e919aa817b075a4f62e58c7ea42a08b90f4fde0f359ac2a20dd6d5f4a0195b49fbac20059502cdc645704253168dff7ac699e06145a839bd9ab5885aec3771a4b4085aec1cd48ff86a8eb10649cbf5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd798624f6d5d4b27fce", + "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" + } + ] + }, + { + "seqno": 170, + "wire": "88cbc36c96c361be940094d27eea0801128005c033704053168dffe50f0d846da642cf588ca47e561cc58190b40081c77f6496dc34fd280129a4fdd41002ca8005c033704fa98b46ffd1408721eaa8a4498f5788ea52d6b0e83772ffcb", + "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" + } + ] + }, + { + "seqno": 171, + "wire": "88cfc76c96c361be940094d27eea0801128005c03371b1298b46ffe90f0d84101d007f588ca47e561cc58190b40081f67f6496dc34fd280129a4fdd41002ca8005c03371b6d4c5a37fd5c1ce", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "88d27f0ca6adaaeb9e4a3c11566fbfdcbf29544f3ad3aab802aaee05598560b23238ebc56c4cac0f216c9f5886a8eb10649cbfe5ed0f0d8365b75dd76401300f28ff9501c7be00b2d85f69f6c416de02a01042d89f540d09e75e75c540e09c0b2d36a819085b13ca81a13ce3c26550382700d34caa064216c4eaa0684f38f002a81c10197c0f2a008596c2fb4fb62744e3ea804fbc1540d2c1540e015032fbc0540d2c1540e015032fbafaa06960aa0700a81971e795034b0550380540c89b6d5034b055038054010b2d85f69f6da0bae015008216dd6d5034b0550380540c85b13aa81a582a81c02a065e13ea81a582a81c02a065f0895034b0550380540cbc2755034b0550380540cbceb8a81a582a81c02a065e136a81a582a81c02a065a659540d2c1540e015032171b0aa06960aa0700a8190b8d815034b0550380fb52f9e919aa82919aa5cb18fd589a5721e9fb5358d33c0c589a7cd", + "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" + } + ] + }, + { + "seqno": 173, + "wire": "88d5cd6c96d07abe9413ea6a2254100225041b8266e34f298b46ffef0f0d836c2cbd588ca47e561cc581908591084fff6496df697e9413ea6a22541002ca820dc10ae36253168dff6196dc34fd280654d27eea0801128166e322b82654c5a37fc8d5", + "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" + } + ] + }, + { + "seqno": 174, + "wire": "88be6c96df3dbf4a01a535112a0800754106e34d5c65f53168dfdbe6e50f0d83642ebf6496c361be940b4a5f2914100225040b8066e05b53168dffe40f138ffe40cc820cad025948f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 175, + "wire": "88db0f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645704ca98b46ffb5358d33c0c7fd2d1d35f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e0f0d8374006bc16c96d07abe941094d444a820044a099b806ae044a62d1bff40884d83a903224c7abfcab7aaf67fb700ec7ffdfffa8fada4a64c922984d5486aa6d761e4b489eed7d6da0f364914adaae937855c0744c6faace1b7aaf62a2bae01d8d57702ae010b059191c75e24627560798ddf7f0aa44b96d04afa762747d5670dbd55700191d14aa8ae844ab808d60b23238ebc503e5581e480d3d2", + "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" + } + ] + }, + { + "seqno": 176, + "wire": "88c46496dd6d5f4a09b5349fba820044a099b8d3b700053168df6c96c361be9413aa436cca0801028005c10ae36d298b46ffe2edecea0f0d033336360f1390fe5e00e513e57e523d21081b8f15afe7d0", + "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" + } + ] + }, + { + "seqno": 177, + "wire": "8bc66496c361be94138a6a225410022500d5c699b8c854c5a37f6c96df3dbf4a01c535112a08006d4106e09fb81694c5a37fe4ef0f1391fe5e04b1b8f95d65c71a2321b8e4a5fe7fee0f0d820b41ecd2", + "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" + } + ] + }, + { + "seqno": 178, + "wire": "88c86c96d07abe94136a65b685040036a0817190dc69953168dfe5f0ef0f0d0236346497dd6d5f4a09b5349fba820044a099b8d3971b7d4c5a37ffee0f138ffe40cc820cad025948f86e37187f9f", + "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\"" + } + ] + }, + { + "seqno": 179, + "wire": "88ca6496dd6d5f4a05e5349fba820044a085704f5c034a62d1bf6c96df697e94136a6e2d6a080112806ee05cb81794c5a37f5f87352398ac5754dff4f3f10f0d8375c1330f138ffe40471e7a371b0b448c371b79cfe7", + "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\"" + } + ] + }, + { + "seqno": 180, + "wire": "88e8e06c96c361be940bea6a2254100225042b8d8ae32253168dff5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d03393439588ca47e561cc5819009d65c083f6496dc34fd2817d4d444a8200595042b8d8ae32253168dffefdbe8", + "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" + } + ] + }, + { + "seqno": 181, + "wire": "885f911d75d0620d263d4c795ba0fb8d04b0d5a76c96df697e940bea65b6a50400894037700f5c684a62d1bf52848fd24a8f768dd06258741e54ad9326e61c5c1fe80f0d83081c7fec588ca47e561cc5802fb8e8190bdf6496e4593e940bea65b6a50400b2a01bb8c86e002a62d1bfd7e1", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "88f2ea6c96df3dbf4a09b535112a0801128066e05ab82654c5a37fc70f0d8371f643588ca47e561cc581903a20b217ff6496c361be94136a6a22541002ca8066e05ab821298b46ffdae4f1", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "88f54083b283cd9cb6755c074eaab37dfefd3e52871d5c4165972612c1646471d78a595e408df2b1631fa5ac2f6b4a84ac693fb70b23238ebc558b2bc0586d8c8b01d700b104e02594206a364bfc0fa0fcae3a285e62a7f808177c0b85f12e10bdfc1631fa5c87a7ff7ffc5f8b1d75d0620d263d4c7441eaeb6196dc34fd280654d27eea0801128166e322b82694c5a37f", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "886196dc34fd280654d27eea0801128166e322b826d4c5a37fd26c96df3dbf4a01a535112a080112817ae36e5c65c53168df5f87352398ac4c697fcbca588ba47e561cc581979e7800070f0d837db1070f138ffe40471e7a371b0b448c371b79cfe7", + "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\"" + } + ] + }, + { + "seqno": 185, + "wire": "88768c86b19272ad78fe8e92b015c37f1eabadaa9570165bd25b64a3c11566fbf6d4abb85a99c6d5700a89e6471aacdf582c8c8e3af1657c2b03c85f27588caec3771a4bf4a547588324e5f65f87497ca58e883d5ff4c5", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "88c10f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc6457190298b46ffb5358d33c0c7ff8f7f9f60f0d847c0265bf6196dc34fd280654d27eea0801128166e322b8c814c5a37fe3e2e1f6f5", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "8b6196dc34fd280654d27eea0801128166e322b8c854c5a37f6496df3dbf4a09d53716b50400894133702ddc680a62d1bf6c96c361be941054ca3a94100215040b8d8ae36253168dffc7d4d3c60f0d033336360f1390fe4031baf0a31c91be48c371c785fcfff4", + "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" + } + ] + }, + { + "seqno": 188, + "wire": "88c50f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc6457191298b46ffb5358d33c0c7f5885aec3771a4b4085aec1cd48ff86a8eb10649cbf5a839bd9abea0f0d8478006c1fc3e97f29c7b7aaf67fb700ec7ffd98ff5b494c99245309aa90d54daec3c96913ddafadb41e6c92295b55d26f0ab80e898df559c36f55ec54575c03b1aaee098eb059191c75f00c60581e6373e85b842d4b70dd798624f6d5d4b27f", + "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" + } + ] + }, + { + "seqno": 189, + "wire": "8b6196dc34fd280654d27eea0801128166e322b8c894c5a37fe8e7cedbdacd0f0d033336360f1390fe4031baf0a31c91be48c371c785fcff408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 190, + "wire": "88bf6496c361be940b4a5f291410022502cdc659b80654c5a37f6c96e4593e940094d03f4a0801128266e01fb827d4c5a37fcfd05f88352398ac74acb37f0f0d830b6d35", + "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" + } + ] + }, + { + "seqno": 191, + "wire": "88d07f10a9adaa9570165bd25b64a3c11566fbf6d4abb85a99c6d5700a89e204b32c1646471d7c20902b03c85d7fcfc8d3c4c30f0d023432", + "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" + } + ] + }, + { + "seqno": 192, + "wire": "88d16c96df697e9413ea681fa50400894106e32cdc65a53168dfc00f0d8369f03d588ba47e561cc581e640dbc26b6496df3dbf4a01d53096350400b2a05cb8d0ae36ea98b46f6196dc34fd280654d27eea0801128166e322b8cb2a62d1bfc6", + "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" + } + ] + }, + { + "seqno": 193, + "wire": "88d50f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645719714c5a37fda9ac699e063fcdcccb5f91497ca589d34d1f649c7620a98386fc2b3d0f0d847c21641f6196dc34fd280654d27eea0801128166e322b8cb8a62d1bf6c96d07abe941094d444a820044a099b806ae044a62d1bffcdf7cccb", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "8b6196dc34fd280654d27eea0801128166e322b8cbaa62d1bfd3d2dbe8e7da0f0d033336360f1390fe4031baf0a31c91be48c371c785fcffca", + "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" + } + ] + }, + { + "seqno": 195, + "wire": "88d90f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc645719754c5a37fda9ac699e063fd1d0cf5f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e0f0d847800701fbfc07f10c6eea2f67fb702e4824dbf5b494c99245309aa90d54daec3c96913ddafadb41e6c92295b55d26f0ab80e898df559c3dd5770af62a2bae05c9049b560b23238ebe19657d60798c97f09a44b96d04afa762747d5670dbd55700191d14aa8ae844ab808d60b23238ebc503e5581e480d0cf", + "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" + } + ] + }, + { + "seqno": 196, + "wire": "8b6196dc34fd280654d27eea0801128166e322b8cbca62d1bf6496c361be94138a6a225410022500d5c699b8c854c5a37f6c96df3dbf4a01c535112a08006d4106e09fb81694c5a37fe1eeede00f0d033336360f1390fe4031baf0a31c91be48c371c785fcffd0", + "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" + } + ] + }, + { + "seqno": 197, + "wire": "88df6c96d07abe9413aa6e2d6a080102807ee01db82694c5a37ff4d4d60f0d83089f077b8b84842d695b05443c86aa6f5892aec3771a4bf4a523f2b0e62c0c85b65c00016497dd6d5f4a0195349fba820059502cdc6457197d4c5a37ff6196dc34fd280654d27eea0801128166e322b8cbea62d1bfd5408a224a7aaa4ad416a9933f8369b79e", + "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" + } + ] + }, + { + "seqno": 198, + "wire": "88e57f08aaadaa9570165bd25b64a3c11566fbf6d4abb85a99c715700a89e664640b059191c75f13d21160790beeffe4dde8d9c00f0d0234320f28faaab31a08d335a6918238ebcf332842c8c036dc7dc68ae34e11c96518c23205b13ae36075efff0935a6918238ebcf364702c8c0300df95c6dc7a30b92cadbe174a56c4eb8d81d7bffcfb52f9e919aa8172c63f4b90f4fda983cd66b0a88375b57d280656d27eeb08016540b371915c680a62d1bfed4d634cf031f4003703370d2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a437f40d4bf8388d4d7baf9d4d7ba11a9ab86d53743a0ea64d37d4e1a72297b568534c3c54c9a77a9bb7c2a5fc1a14d7b707f3", + "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\"" + } + ] + }, + { + "seqno": 199, + "wire": "88e70f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc6457197d4c5a37fda9ac699e063fdfdeddcf0f0d847c2171bfc1cdcac9dbda", + "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" + } + ] + }, + { + "seqno": 200, + "wire": "88e77f00aaadaa9570165bd25b64a3c11566fbf6d4abb85a99c6d5700a89e6db6e5582c8c8e3af8a40b6b03c85e93fe6dfeadb6196dc34fd280654d27eea0801128166e322b8d054c5a37f0f0d0234320f28faaab31a08c935a6918238ebcf364702c8c0300df95c6dc7a30b92cadbe174a56c4eb8d81d7fffc4cd69a4608e3af3ccca10b2300db71f71a2b8d384725946308c816c4eb8d81d7fffcfb52f9e919aa8172c63f4b90f4fda983cd66b0a88375b57d280656d27eeb08016540b371915c682a62d1bfed4d634cf031fc0", + "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\"" + } + ] + }, + { + "seqno": 201, + "wire": "48826401ea0f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc64571a1298b46ffb5358d33c0c7fe2e10f1f9e9d29aee30c78f1e172c63f4b90f4b128d1398f531394742675a328ed4faf7f01a2adaae937855c0744c6faace1eeabb857f0422ae0249dd12acde582c8c8e3afb2d0050f0d01306196dc34fd280654d27eea0801128166e322b8d094c5a37f", + "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" + } + ] + }, + { + "seqno": 202, + "wire": "88ec0f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc64571a654c5a37fda9ac699e063f5886a8eb10649cbfe4e3d50f0d84089d7c5f6196dc34fd280654d27eea0801128166e322b8d32a62d1bfd4d17f02a8adab557009474966eb5ca6b65559c2ab3793d9513ddbb2f22ae01b995700db2b059191c75f659724e3e2", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88bf6497dd6d5f4a09b5349fba820044a099b8d3b71a6d4c5a37ff6c96df3dbf4a01b532db42820044a05eb8d33702f298b46f5f87352398ac5754df52848fd24a8f768dd06258741e54ad9326e61c5c1ff50f0d83134e3f", + "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" + } + ] + }, + { + "seqno": 204, + "wire": "88f46c96df3dbf4a09a5340fd2820044a05cb8215c13aa62d1bfe30f0d836de6c1588ca47e561cc58190b607df6dcf6497dd6d5f4a0195349fba820059500e5c0bd7197d4c5a37ffc7e854012a", + "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": "*" + } + ] + }, + { + "seqno": 205, + "wire": "88768c86b19272ad78fe8e92b015c3d75f90497ca582211f649c7620a98386fc2b3deef00f0d836dc75fd75892aed8e8313e94a47e561cc58190b6cb80003f6497dd6d5f4a0195349fba820059502cdc64571a654c5a37ffccedd5", + "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" + } + ] + }, + { + "seqno": 206, + "wire": "88c16c96dc34fd282754d444a820044a05bb8db571b694c5a37feb0f0d8371910b588ca47e561cc58190b62105f77f6496dd6d5f4a0195349fba820059500fdc68571a0298b46fcff0c5", + "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": "*" + } + ] + }, + { + "seqno": 207, + "wire": "88c47f0fa3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301da960b23191f8df23a0581e42eb9f6c96e4593e94134a6a2254100225042b827ee05f53168dff7f19c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f95f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d821360588ca47e561cc581908402036cff6496df697e9413ea6a22541002ca8166e001702e298b46ffd5f65a839bd9abe3", + "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" + } + ] + }, + { + "seqno": 208, + "wire": "88cb6c96d07abe94138a5f291410021502edc659b826d4c5a37ff50f0d836df003588ca47e561cc58190b6069e0b9f6497dd6d5f4a0195349fba820059500d5c6c571b7d4c5a37ffd9408721eaa8a4498f5788ea52d6b0e83772ffd0", + "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": "*" + } + ] + }, + { + "seqno": 209, + "wire": "88cf6c96d07abe9413ea6a225410022502ddc64571b794c5a37f5f88352398ac74acb37f0f0d8365f6d9588ca47e561cc58190b610bc16ff6497dd6d5f4a0195349fba820059500e5c69fb8cbca62d1bffdec2d4", + "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": "*" + } + ] + }, + { + "seqno": 210, + "wire": "88d36c96c361be940894d444a820044a05db8cbb700f298b46ffc10f0d8369a0bd588ca47e561cc5804fb8265c7c5f6496dc34fd281129a88950400b2a0417040b8db6a62d1bffe1c5", + "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" + } + ] + }, + { + "seqno": 211, + "wire": "88d6ef5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf5b842d4b70ddf0cb0f0d840800fbdfefd5e3c7", + "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" + } + ] + }, + { + "seqno": 212, + "wire": "88e36c96df697e9403aa436cca080112820dc006e09b53168dffe0df0f1390fe5e034065f216495d689206e38067f9de0f0d850859138e7f", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "88d96c96df697e9403aa436cca080112806ee09fb8db6a62d1bfc70f0d83759683588ca47e561cc5802fb2f3816ddf6496dc34fd2816d4cb6d4a080165410ae32ddc1014c5a37fe7cbdd", + "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": "*" + } + ] + }, + { + "seqno": 214, + "wire": "88dc6c96df697e94132a6a2254100225041b8dbb702da98b46ffca0f0d8375a705588ca47e561cc58190b6079b65af6497dd6d5f4a0195349fba820059500ddc6dab8dbaa62d1bffeacee0", + "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": "*" + } + ] + }, + { + "seqno": 215, + "wire": "88df6c96d07abe9413ea6a2254100225002b8cbf704e298b46ffcd0f0d840800f83f588ca47e561cc58190b600b217bf6497dd6d5f4a0195349fba820059500cdc6dab8d054c5a37ffedd1e3", + "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": "*" + } + ] + }, + { + "seqno": 216, + "wire": "88e2d56c96df697e940b8a6a225410022502fdc64571a6d4c5a37fe20f0d8371975d588ba47e561cc58190000268026496e4593e940b8a6a22541002ca817ee322b8d36a62d1bff0d47b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "88e66c96df697e9413ea681fa504008940bf71a05c03aa62d1bfd40f0d8369a79e588ba47e561cc581d138065f6f6496dc34fd282714ca3a941002ca816ae05fb81794c5a37ff4d8", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "88e96c96c361be941014cb6d0a0801128266e09fb8cbca62d1bfd70f0d8369e79f588ca47e561cc5802fbe079a103f6496c361be941054cb6d4a08016541337197ee34ca98b46ff7db", + "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" + } + ] + }, + { + "seqno": 219, + "wire": "88ec6c96df697e9403ea6a225410022502d5c00ae05d53168dffda0f0d8365c65e588ca47e561cc5804f36075e781f6496dd6d5f4a09f53716b50400b2a045704d5c032a62d1bf6196dc34fd280654d27eea0801128166e322b8d32a62d1bfdf", + "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" + } + ] + }, + { + "seqno": 220, + "wire": "88f06c96df697e940094d444a820044a05eb8015c03ca62d1bffde0f0d836d96dc588ca47e561cc5804f85f79f7dbf6496d07abe9403aa6a22541002ca8115c10ae32f298b46ffc1e2f4", + "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": "*" + } + ] + }, + { + "seqno": 221, + "wire": "88f36c96df3dbf4a044a65b6850400894006e36e5c038a62d1bfe10f0d8369c03b588ca47e561cc5804069913e06ff6496c361be9413ca65b6a50400b2a0037041b80794c5a37fc4e5", + "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" + } + ] + }, + { + "seqno": 222, + "wire": "88f66c96d07abe94132a65b68504008940b9702f5c03ca62d1bfe40f0d836c227b588ca47e561cc5804cbacbceb40f6496d07abe94036a436cca080165403b7197ae09953168dfc7e8", + "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" + } + ] + }, + { + "seqno": 223, + "wire": "88f96c96d07abe9413ea6a225410022502e5c69ab8cb6a62d1bfe70f0d8375e7c5588ca47e561cc58190b6cb4ebeff6496dd6d5f4a0195349fba820059502cdc08ae34253168dfcaeb54012a", + "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": "*" + } + ] + }, + { + "seqno": 224, + "wire": "88768c86b19272ad78fe8e92b015c36c96df697e940b8a6a225410022500cdc659b82654c5a37fec0f0d83684cb5588ca47e561cc5804fba271a79ef6496dd6d5f4a059535112a08016540b571b6ae042a62d1bfcff0", + "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" + } + ] + }, + { + "seqno": 225, + "wire": "88c16c96d07abe94101486d994100225040b8272e34fa98b46ffef0f0d8364020f588ca47e561cc5804e080d32d8bf6496d07abe940094dc5ad41002ca8205c64371b6d4c5a37fd2f3", + "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" + } + ] + }, + { + "seqno": 226, + "wire": "88c46c96c361be9413ca6e2d6a080112816ee085704da98b46fff20f0d8369f0bf588ca47e561cc581903a17dc79ff6496c361be94136a6a22541002ca8015c69db8c894c5a37fd5f6", + "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" + } + ] + }, + { + "seqno": 227, + "wire": "88c76c96dd6d5f4a084a65b68504008940bd702cdc136a62d1bff50f0d8369d79e588ca47e561cc580407990b816ff6496df697e940094cb6d0a08016540b9700e5c0bea62d1bf6196dc34fd280654d27eea0801128166e322b8d34a62d1bffa", + "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" + } + ] + }, + { + "seqno": 228, + "wire": "88cb6c96c361be94038a65b6850400894102e05bb82794c5a37ff90f0d8365f79d588ca47e561cc5802ebceb2fb20f6496e4593e9413ea681fa50400b2a0417190dc65a53168dfc1408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 229, + "wire": "88cf6c96df3dbf4a05c521b66504008940b571b66e002a62d1bf5f88352398ac74acb37f0f0d8369c133588ca47e561cc5804069d75c6dbf6497c361be9413ca65b6a50400b2a059b8d3971b7d4c5a37ffc6c2", + "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" + } + ] + }, + { + "seqno": 230, + "wire": "88d36c96c361be9413aa65b68504008940bb71b7ae01b53168dfc10f0d8369e107588ca47e561cc5804069f7dd65ef6496c361be9413ca65b6a50400b2a05fb8db7700253168dfc9c5", + "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" + } + ] + }, + { + "seqno": 231, + "wire": "88d66c96c361be940b2a65b685040089403771976e09a53168dfc40f0d836c0f03588ca47e561cc5802fbcf3a269bf6496c361be941054cb6d4a08016540bb71a72e34fa98b46fccc8", + "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" + } + ] + }, + { + "seqno": 232, + "wire": "885f911d75d0620d263d4c795ba0fb8d04b0d5a76c96c361be940094d27eea080112817ee00571b1298b46ff52848fd24a8f768dd06258741e54ad9326e61c5c1f5a839bd9ab0f0d840bcf38cff6588aa47e561cc581a03cd83f6496dd6d5f4a01a5349fba820044a00171b66e32ca98b46feecf", + "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" + } + ] + }, + { + "seqno": 233, + "wire": "88e06c96df3dbf4a09d53716b504008940b3704d5c680a62d1bfce0f0d840800c83f588ca47e561cc58190b620b6217f6496dd6d5f4a0195349fba820059500fdc643704da98b46ff1d2e4", + "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": "*" + } + ] + }, + { + "seqno": 234, + "wire": "88e36c96d07abe940b8a65b685040089403b700d5c0bea62d1bfd10f0d83719103588ca47e561cc5804cb2eb2269df6496df3dbf4a002a436cca080165400ae01cb8d854c5a37fd9d5e7", + "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": "*" + } + ] + }, + { + "seqno": 235, + "wire": "88e64085b283cc693fa5adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1332abb802b0591b25944fbefbab03c85c93f6c96c361be94036a6a225410022500ddc0bb704153168dff4003703370c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f9d60f0d84700113bf588ca47e561cc5804f89c1082e7f6496df697e9403ca6a22541002ca806ee36e5c0bea62d1bff9dacb7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 236, + "wire": "88ec6c96df697e940814cb6d0a080112820dc13d71a714c5a37fda0f0d836df799588ca47e561cc5804cbacbcf89cf6496d07abe94036a436cca080165403b71a0dc13ea62d1bf6196dc34fd280654d27eea0801128166e322b8d32a62d1bfdf", + "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" + } + ] + }, + { + "seqno": 237, + "wire": "88f0f16c96dc34fd282754d444a820044a05ab8d86e32d298b46ffde0f0d84085e7dbf588ca47e561cc58190b610000dff6496dd6d5f4a0195349fba820059500e5c0bf704f298b46fc1e2", + "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" + } + ] + }, + { + "seqno": 238, + "wire": "88f36c96d07abe941094d444a820044a01eb8d39700da98b46ffe10f0d8375c75a588ca47e561cc5819089a6dd13bf6496df3dbf4a321535112a080165403571b6ae36053168dfc4e5", + "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" + } + ] + }, + { + "seqno": 239, + "wire": "88f66c96e4593e9403ca436cca080112817ae08171a714c5a37fe40f0d84089d69af588ca47e561cc5804e32f3cf019f6496e4593e94034a6e2d6a080165413371a72e01c53168dfc7e8", + "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" + } + ] + }, + { + "seqno": 240, + "wire": "88f96c96d07abe9413aa436cca080112817ee32f5c69953168dfe70f0d836de6c5588ca47e561cc5804eb2f34d362f6496d07abe940b8a6e2d6a080165408ae081702da98b46ffcaeb", + "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" + } + ] + }, + { + "seqno": 241, + "wire": "88768c86b19272ad78fe8e92b015c354012a6c96df697e941094d27eea08010a817ae322b80754c5a37fec0f0d83700173588ca47e561cc58190b606da685f6496dd6d5f4a0195349fba820059500ddc033704da98b46fcff0", + "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" + } + ] + }, + { + "seqno": 242, + "wire": "88c26c96dd6d5f4a09953716b50400894102e09db807d4c5a37fef0f0d8379d683588ca47e561cc5804f044f01f0ff6496e4593e94136a6e2d6a080165400ae36d5c0b4a62d1bfd2f3", + "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" + } + ] + }, + { + "seqno": 243, + "wire": "88c5c46c96df3dbf4a09b535112a080112817ae36cdc13ca62d1bff20f0d836dd13b588ca47e561cc58190b6013a267f6496dd6d5f4a0195349fba820059500d5c0bd700e298b46fd5f6", + "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" + } + ] + }, + { + "seqno": 244, + "wire": "88c8e76c96df697e940b8a6a225410022502fdc64571a714c5a37f5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ec938ec4153070df8567bf0f0d846da682f7588ca47e561cc5819000026997ff6496e4593e940b8a6a22541002ca817ee32cdc1094c5a37fd9fadd", + "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" + } + ] + }, + { + "seqno": 245, + "wire": "886196dc34fd280654d27eea0801128166e322b8d34a62d1bf6c96df697e941094d03f4a080112817ee00571b654c5a37f5f87352398ac5754dff0ef0f0d83109e7b", + "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" + } + ] + }, + { + "seqno": 246, + "wire": "88c06497dd6d5f4a09b5349fba820044a099b8d3971b714c5a37ff6c96e4593e94642a436cca08010a8005c65fb816d4c5a37fc0f2f1588ba47e561cc581979e7800070f0d836dd699", + "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" + } + ] + }, + { + "seqno": 247, + "wire": "88d26c96dd6d5f4a05b532db42820044a01bb8272e09d53168df5f88352398ac74acb37f0f0d83702eb5588ca47e561cc58040700e05e0ff6496dd6d5f4a320532db528200595001b827ee01b53168dfc7408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 248, + "wire": "88d76c96dd6d5f4a09e535112a0801128205c0b371a0298b46ffc20f0d83782f0b588ca47e561cc581903c0138eb5f6496dc34fd282714d444a8200595001b8d82e32f298b46ffcbc1", + "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" + } + ] + }, + { + "seqno": 249, + "wire": "88da7f31a3adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1301c6d60b2f8425209c8cab03c85c93f6c96e4593e9403ca436cca080112820dc685702fa98b46fff0c60f0d846de71973588ba47e561cc5804d08217c026496dc34fd2810290db32820059502fdc035704da98b46ffebc5", + "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" + } + ] + }, + { + "seqno": 250, + "wire": "88cf6c96e4593e94032a6a2254100225042b806ee36053168dffce52848fd24a8f0f1390fe5e034065f216495d689206e38067f9768dd06258741e54ad9326e61c5c1f0f0d847197c0ff", + "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" + } + ] + }, + { + "seqno": 251, + "wire": "88e1e06c96d07abe9413ea6a225410022502ddc6deb8d814c5a37fcc0f0d840b2003df588ca47e561cc58190b6cb6f85ff6496dd6d5f4a0195349fba820059502cdc643704253168dff1cb", + "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" + } + ] + }, + { + "seqno": 252, + "wire": "88e47f08a7adaa9570165bd25b64a3c11566fbfdd3f29438eaed15c940502c1646471d7d99596560790bf1ff588caec3771a4bf4a547588324e54085aec1cd48ff86a8eb10649cbf5f87352398ac4c697f798624f6d5d4b27f6196dc34fd280654d27eea0801128166e322b8d36a62d1bf0f0d0234320f28faaab31a08d335a6918238ebcf332842c8c036dc7dc68ae34e11c96518c23205b13ae360764fff0935a6918238ebcf364702c8c0300df95c6dc7a30b92cadbe174a56c4eb8d81d93ffcfb52f9e919aa8172c63f4b90f4fda983cd66b0a88375b57d280656d27eeb08016540b371915c69b53168dff6a6b1a67818f4003703370d2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a437f40d4bf8388d4d7baf9d4d7ba11a9ab86d53743a0ea64d37d4e1a72297b568534c3c54c9a77a9bb7c2a5fc1a14d7b707f3", + "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\"" + } + ] + }, + { + "seqno": 253, + "wire": "88eb7f05a5adaaeb9e4a3c11566fbf6aaee0f94aa279d6c1332abb84eb0591b4075d136d8960790b8fff6c96c361be94036a6a225410022500ddc0bf702d298b46ff7f01c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f9d80f0d85085b79c6bf588ca47e561cc5804f89e75d6dff6496df697e9403ca6a22541002ca8166e005700253168dff6196dc34fd280654d27eea0801128166e322b8d32a62d1bfd8", + "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" + } + ] + }, + { + "seqno": 254, + "wire": "880f0d8313a067e06c96e4593e9413ca681d8a0801128215c641702ca98b46ffd0cfe36496df697e94640a6a225410022502fdc13b704fa98b46ffda", + "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" + } + ] + }, + { + "seqno": 255, + "wire": "88f30f28bca2d275f4fc017db7de7c1f6a5f3d2335502e58c7e9721e9fb53079acd615106f9edfa50025b49fbac2005d502cdc64571b794c5a37fda9ac699e063f5885aec3771a4bcb5a839bd9ab5f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e0f0d84780071af6196dc34fd280654d27eea0801128166e322b8dbca62d1bf6c96d07abe941094d444a820044a099b806ae044a62d1bff40884d83a903224c7abfcab7aaf67fb700ec7ffdebff3eb692993248a6135521aa9b5d8792d227bb5f5b683cd92452b6aba4de15701d131beab386deabd8a8aeb8076355dc1d5576f2c1646471d7dc9647160792077f0ca8adab557009474966eb5ca6b65559c2ab3793d9513ddbb2f22ae01b995700db2b059191c75f6597245b842d4b70ddd0", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_26.json b/http/http-client/src/test/resources/hpack-test-case/story_26.json new file mode 100644 index 0000000000..24eb00ef87 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_26.json @@ -0,0 +1,4673 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "8854012a0f0d826c425f87352398ac4c697f6c96df3dbf4a044a435d8a0801128066e019b820298b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb4088f2b4b1ad2163b66fa4c9c4ac6ef16932db7519d3c71f2cbe05af449ab7eaf36e0e5c0d63669b669df3f5df341f4087f2b12a291263d5842507417f5892aed8e8313e94a47e561cc5802e882e3ce3ff6496df697e941054d03f4a08016540bf702f5c65953168df6196dc34fd280654d27eea0801128115c6c171a694c5a37f408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88c75f91497ca582211f6a1271d882a60b532acf7f6c96df697e94134a435d8a0801128215c0b37196d4c5a37fc67f06a37db4f0f54c83930e791ebf5d343dc6ad47e189dcd3991abc7575acd2303c98a5e0083fc57b8b84842d695b05443c86aa6f5a839bd9ab0f0d8208995892aed8e8313e94a47e561cc5802e32fb4f841f6496dd6d5f4a044a681fa50400b2a01cb8dbf702d298b46fc6c5", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "88cec46c96dd6d5f4a09e535112a080112820dc65db8cb6a62d1bfccc17f04a2d8406227037833263bc3ddb7249f831cfcec733669eb9fbf1734d1a5eee7623bed410f0d840b4e3cd75892aed8e8313e94a47e561cc5819081c75c65bf6496df697e9413ea6a22541002ca8015c69ab8cbea62d1bfcac9c5", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88d25f87352398ac5754df6c96df3dbf4a044a435d8a0801128066e019b82654c5a37fd17f03a474be7876ea7fdf29973a0bb43ef3f9cb47e555f3cce68d479aafdb6f66f2ec9649b4f07f0f0d840b4d32f75892aed8e8313e94a47e561cc5804d3e271b701f6496d07abe940bea436cca0801654002e36cdc134a62d1bfcfce", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88d75f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559ef6c96d07abe9413ea6a225410022502edc03d71b714c5a37fd6cb7f03a62edefeb2e7fcc9df933c6d7e4ff74b4cbfdffde7c59bb7e1b3eecd4fb77c3ec79d10f0ac907f0f0d840bad3adf5892aed8e8313e94a47e561cc58190844d34277f6496df697e9413ea6a22541002ca817ae321b810a98b46ffd4d3cf", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88dcd26c96dd6d5f4a09e535112a0801128215c6dbb82754c5a37fdacf7f02a40b539f013d78d3a745dc9c786e6eebb0df776dfc46bfdf2b5771175719b2c776ffb941070f0d8469a0be1fcbcad6d5d1", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88dec46c96c361be940894d444a820044a05eb8cb571a794c5a37fdc7f00a3682c63b71130e9d14fa4344ef8b35174bea83f4938dfd6d7fbe37724a198d6b25d3b200f0d033735345892aed8e8313e94a47e561cc5804fbef361705f6496e4593e940b8a6a22541002ca816ae019b8c854c5a37f6196dc34fd280654d27eea0801128115c6c171a7d4c5a37fdad5d6", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88e3ce6c96df3dbf4a09b535112a0801128172e01bb8db2a62d1bfe17f03a53e6d9e3b832e7e67427fdfbed4777bcffbbcee8c19ddf7b6ec65d07a4e46dad0dedfde707fe0d8d70f0d83132d3f5892aed8e8313e94a47e561cc5819081c759703f6496df697e9413ea6a22541002ca8015c681702053168dffc2de", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88e70f0d83138273cd6c96dd6d5f4a09e535112a080112820dc03d71b0298b46ffe57f02a4f73bc9db8f3614e0db93f7fde660b88da036a690e371cd556ae81ede35c3a5dbdd5f860fe45892aed8e8313e94a47e561cc5819081c79b741f6496df697e9413ea6a22541002ca8066e001702fa98b46ffc6e2ddde", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88ebd66c96c361be9413ca6e2d6a080112816ee003702d298b46ffe9de7f02a2aec313b6424f8fda71f9cd0ecdc69361bc62a76cae0bbc39dcc8eea302c633180f410f0d83780cb95892aed8e8313e94a47e561cc5819081c71f681f6496df697e9413ea6a22541002ca8015c659b807d4c5a37fcae6e2", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88efd56c96dc34fd282754d444a820044a08371a15c0bea62d1bffede27f02a5cd6d82c3c386ce90ec07ad7b32de7e5ef99b718ff79f97ee3efeb66172f14586d1ca2eb07f0f0d8465c6402f5892aed8e8313e94a47e561cc5819081c79a741f6496df697e9413ea6a22541002ca8015c6deb8cbea62d1bfceeae6", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88f3de6c96df3dbf4a044a435d8a0801128066e00571b0a98b46fff1e67f02a3f1d45a397a4659fc33812ededb8b44214607f1f2b7d7bf4f1ef774ef17174daff0b3410f0d83784c835892aed8e8313e94a47e561cc5804db8cbee3eff6496df697e9413aa436cca080165403971b7ee01e53168dfd2eeea", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "8854012ade6c96dc34fd282754d444a820044a0837197ae34d298b46fff6eb7f03a4c5a3dfbf5d0175e7f3f3943ef3637e7ede7f4bd7db74f3df4a2df3e33db372f441629a0f0f0d8369e75e5892aed8e8313e94a47e561cc5819081c79b13ff6496df697e9413ea6a22541002ca8015c6dfb8cbca62d1bfd7f3ef", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "886c96dc34fd280654d27eea080112806ae32edc69e53168df6496dc34fd281029a4fdd410022500d5c65db8d3ca62d1bf5f911d75d0620d263d4c1c88ad6b0a8acf520b409221ea496a4ac9b0752252d8b16a21e435537f858cd50ecf5f0f0d830bc16b58a7a47e561cc581b75b105bfa52bb63a0c4fa52a3ac9b0752253d94fd294da84ad617b8e83483497f6196dc34fd280654d27eea0801128115c6c171b654c5a37f4087aaa21ca4498f57842507417f408721eaa8a4498f5788cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "8858bbaec3771a4bf4a54759093d85fa52a3ac419272fd294da84ad617b8e83483497e94ace84ac49ca4eb003e94aec2ac49ca4eb003e94a47e561cc58015f87352398ac4c697f6495df3dbf4a05486bb141000d2800dc006e002a62d1bf6c95df3dbf4a05486bb141000d2800dc006e000a62d1bf4085aec1cd48ff86a8eb10649cbf4089f2b4b1ad495361888f1c7b2277223a35332c2272223a32362c2271223a302c2261223a32357d4089f2b4b1ac82d9dcb67f88081775a5de7d71337f10a474d9fa23671fc45b570cdf85674d1c45e923bb8bdec071c77bae8fc632b9660b6eb9ce0f6196dc34fd280654d27eea0801128115c6c171b694c5a37f7f0888ea52d6b0e83772ff0f0d023433", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88d45f91497ca582211f6a1271d882a60b532acf7f6c96dd6d5f4a09e535112a080112816ee01cb8db2a62d1bf4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb5a839bd9ab7f05a4b6cff7bf1d18719739d28a6fd1b3973d7e058b6e0cfebbcc27b2d3801979f14b6e5a783f0f0d83085b6f5892aed8e8313e94a47e561cc5819081c75d0b5f6496df697e9413ea6a22541002ca8015c69cb80794c5a37fc6c57b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "88dcc56c96c361be94642a436cca0801128215c0b3704f298b46ffc47f03a471897363ebb5376bded1fb5d999653871f5157a9cdd7ff68e18821e1d9a621a3864c107f0f0d033531365892aed8e8313e94a47e561cc5804e321719035f6496e4593e94034a6e2d6a080165400ae36ddc6de53168dfcbcac6c2", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88e00f0d8213225f87352398ac5754df6c96dc34fd2820a90d762820044a01db8066e36ea98b46ffc97f03a4fc4ef46ad25c58f12180f7dbb7bbc4efa798486bacfe76a2cef56fec2c5fbf9deaeda20f4087f2b12a291263d5842507417f5892aed8e8313e94a47e561cc581903417dc0bff6496d07abe941054d444a820059502d5c69ab8cb6a62d1bf6196dc34fd280654d27eea0801128115c6c171b714c5a37fd1cdc9", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88e7c46c96c361be9403aa6e2d6a080112816ee05eb8d014c5a37fcf7f04a5c02cb779ef1d7ebf30f4f3bf7f1edd6c2f5dfc735fac345fd9b37b0ef3f24f32e9e02e107fc3cbcf0f0d8268005892aed8e8313e94a47e561cc5819081c71f659ff3c1d4", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "88ea5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559ef6c96dc34fd282754d444a820044a08371a0dc69b53168dffd3d27f02a336b8f3c9d075ecf7b4e34c7ab85fb34ffb2f9bfd1ec1af1e58488fd69eaf8a6bb130c10f0d8465b75c735892aed8e8313e94a47e561cc5819081c79f781f6496df697e9413ea6a22541002ca8066e01db81694c5a37fdad9d1", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88efcc6c96dd6d5f4a09e535112a080112816ae32d5c6c0a62d1bfd77f02a4010c0daded11bbe4e37b6d9e1389b03b80bd3fde7df99e938677a4c86fdadd07fb93841f0f0d84081f00bf5892aed8e8313e94a47e561cc5819081c71f71bf6496df697e9413ea6a22541002ca8015c659b8d014c5a37f6196dc34fd280654d27eea0801128115c6c171b6d4c5a37fdedad6", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88f4dd6c96dd6d5f4a09e535112a080112820dc65eb82794c5a37fdcdb7f03a5d62bbd8058f8fe744caf62f5b2b0e3c76f97b4f9a254f0d1f9fb6f37bf30ffbf43d5c4f07f0f0d8369c75c5892aed8e8313e94a47e561cc5819081e79d13df6496df697e9413ea6a22541002ca807ae32e5c134a62d1bfcfe2da", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "8854012ae26c96dd6d5f4a09e535112a080112820dc65db810298b46ffe1e07f03a5f58fdf16080f0cfefac9575db1e7bd7ec84096c726ed1ea1c4d5765dd5d7fd9bfda5ce707f0f0d84101d7c3f5892aed8e8313e94a47e561cc5819081c75c6daf6496df697e9413ea6a22541002ca8015c69bb810298b46ffd4e7df", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88c20f0d840842167fda6c96dd6d5f4a09e535112a080112816ae32d5c69d53168dfe57f02a4b59719d5df361a6aa5d0bb96ef0fc85b2ebbaf6f402baf6e477fd97065f1ab516b73c41fd95892aed8e8313e94a47e561cc5819081c71f79ef6496df697e9413ea6a22541002ca8015c65ab80694c5a37fd8ebe7e3", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88c6f36c96df3dbf4a044a435d8a0801128066e00571b754c5a37fe9e87f02a4e69f5fef795ad5ee54784d3d3dc7969cbfa3f51fad009fcfe1b6f01694e3c11dfb75e0830f0d0234335892aed8e8313e94a47e561cc5804dbadb2dbacf6496e4593e9413ca436cca08016540b571976e01f53168dfdcefe7", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "88cae26c96df3dbf4a044a435d8a0801128066e019b82694c5a37fedec7f02a3f59b0fab3cf8ed74d6d3a35cbcbbf76a93d9c38229f6fc9d3f53ba4a6f1f668a893a200f0d033537315892aed8e8313e94a47e561cc5804dbadb2f043f6496e4593e9413ca436cca08016540b571a0dc03aa62d1bfe0f3eb", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88ce5f87352398ac4c697f6c96df3dbf4a044a435d8a0801128066e019b821298b46fff27f03a4c71d9ebcd5addc7a46ef5937de9e172ed75eee99f67804dedffdf78375eed831b2c3fd600f0d0234335892aed8e8313e94a47e561cc5804dbadb2eba0f6496e4593e9413ca436cca08016540b571a05c138a62d1bfe5408721eaa8a4498f5788ea52d6b0e83772fff5f1", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88d4ec6c96df697e9413ca436cca080112800dc102e000a62d1bff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb5a839bd9ab7f05a12c937692d0d1869e1c9916048a7c673428adfeb8721277b65f310da9d093635e200f0d84089e0bbf5892aed8e8313e94a47e561cc5804e34dbc0683f6496df3dbf4a01b53716b50400b2a05eb817ae05d53168dfecc47b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88dbe96c96dd6d5f4a09e535112a080112820dc03f7190298b46ffc4c37f03a5b3f3f13e72332eb9b4e32b9e3364bfb6eed079e894f0d25c5feeedfd9a1ed92e6d83ff70c10f0d84085c79ef5892aed8e8313e94a47e561cc5819081c79f7c1f6496df697e9413ea6a22541002ca8066e01db82754c5a37f6196dc34fd280654d27eea0801128115c6c171b754c5a37fcac3", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88e00f0d8465b0b8dfee6c96dd6d5f4a09e535112a080112820dc03971a754c5a37fc97f03a49786516923fdb2c976f061ab9e185be280cae9fdf7ff66635efcdabfdf12d608418f641f4087f2b12a291263d5842507417f5892aed8e8313e94a47e561cc5819081c79b107f6496df697e9413ea6a22541002ca8015c6dfb8cbca62d1bfc3cfccc8", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88e5f36c96dd6d5f4a09e535112a080112820dc03b700053168dffcecd7f03a443ffb4e5cd573c5460e99311def3b3df9a27e3a1aa8d462c7313b8659f307f5dc21f107f0f0d830804f75892aed8e8313e94a47e561cc5819085f0bcd3ff6496e4593e94640a6a22541002ca8166e05bb80754c5a37f6196dc34fd280654d27eea0801128115c6c171b794c5a37fd4cd", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "88ea5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559ef6c96dd6d5f4a09e535112a080112820dc03b700f298b46ffd4d37f04a39f46cef0bbe67b6145696e5d5e4b25809797bd9fba73f5f46f7c534528afdcdc713d070f0d8469d79a6bcdcccbd7d0", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "88edc06c96d07abe9413ea6a225410022502fdc0bb704d298b46ffd67f00a40e0eb97373cf2f2b483bfc67fdbd838c309db771d70e376cef85ab1fc9e2ffe6815d7a0f0f0d84684cbe1f5892aed8e8313e94a47e561cc5819085a65e645f6496df697e9413ea6a22541002ca8266e36d5c69f53168dfcfdbd8d4", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "88f10f0d840b21783fc46c96dd6d5f4a09e535112a080112820dc082e32253168dffda7f02a493539ab3709597ba5f9130d5becd027bc7eefbbedfe6dcfc18060cb2481bdd7962be883fce5892aed8e8313e94a47e561cc5819081c79f79ffd3c8dedbd7", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "88f4c76c96c361be940094d27eea080112817ee019b8dbaa62d1bfdddc7f01a4c947eb527a233ddd97b5929874f6cb1e12e1dfcb6f5e1df07040b3bd9b3fe691ffb6cf070f0d84132eb2e75892aed8e8313e94a47e561cc58190b4ebccb80f6496dc34fd280129a4fdd41002ca8205c6c1702ea98b46ffd6e2db", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "8854012acc6c96df3dbf4a002a693f750400894102e32ddc13ca62d1bfe2e17f03a3db838fb0756b15b23b1964f7ddfcdbb7e211839b5567b2306f0b54f29d2fb7a326083f0f0d84089f71ff5892aed8e8313e94a47e561cc58190b2fb4f3cdf6496c361be940054d27eea0801654106e32fdc032a62d1bfd1e7e0", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88c2d06c96dd6d5f4a09e535112a080112820dc03971a694c5a37fe6e57f02a4e39bbdbcf3b0fd9dbbf4fc9dda6c7b3f4dd96924db33feb03ff7fa9edd043e08d632120f0f0d8379a6dd5892aed8e8313e94a47e561cc5819081e79d13df6496df697e9413ea6a22541002ca807ae32e5c138a62d1bfd5ebe4", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "8858bbaec3771a4bf4a54759093d85fa52a3ac419272fd294da84ad617b8e83483497e94ace84ac49ca4eb003e94aec2ac49ca4eb003e94a47e561cc5801f16495df3dbf4a05486bb141000d2800dc006e002a62d1bf6c95df3dbf4a05486bb141000d2800dc006e000a62d1bf4085aec1cd48ff86a8eb10649cbf4089f2b4b1ad495361888f1c7b2277223a32362c2272223a31382c2271223a302c2261223a33307d4089f2b4b1ac82d9dcb67f8908170b8d2ef38bb4ff7f07a32cd96c349c6c06a9e6f0cec8f095c72b7a7dfc58fdbe3ff74489b2ce8db7286ff89a0f6196dc34fd280654d27eea0801128115c6c171b7d4c5a37ff30f0d023433", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "88c55f87352398ac4c697fc5c4c37f031c7b2277223a31352c2272223a37342c2271223a302c2261223a32317d7f038908170b8d2e2089779b7f03a4772f18f863c47ca4cfef2478e6eb975f705fdd77d13373e7af59ece04019cd526df0f41fc2408721eaa8a4498f5788ea52d6b0e83772ff0f0d023433", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88ca5f88352398ac74acb37fcac9c87f031c7b2277223a33332c2272223a31342c2271223a302c2261223a32377d7f038a08170b8d2e2032bbcdff7f03a3dd8f09af3363766bfddc7f5b1c877b47773d9edb78e23009b746d3e73e6cd0f1ce483fc7c20f0d84081965af5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88cfc2cecdcc7f021c7b2277223a34372c2272223a32372c2271223a302c2261223a32347d7f028908170b8d2e110576db7f02a4baf6fd826f1e7b2be1a3fd8aab672f4ff6ebef6274d18acfc467f39afeda6991c65c6a0fcbc60f0d8475f005ffc1", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88db0f0d023433ca6c96df3dbf4a044a435d8a0801128066e019b806d4c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb7f01a3ec1e7469d9867e16643031e179e9b0b0869d3277e8bc0873f1dc2339f8760bbb0ec83ff45892aed8e8313e94a47e561cc5802e882e3cdb9f6496df697e941054d03f4a08016540bf702f5c65b53168dfd0cbc67b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "88e1d06c96df3dbf4a044a435d8a0801128066e019b820298b46ffc3c87f03a4d5ab3595f32e50e6116de3cb84c09d9fc6b567bfc3fdc7aff219f1945fb1e6a479321e0f0f0d0234335892aed8e8313e94a47e561cc5802e882e3cdb7f6496df697e941054d03f4a08016540bf702f5c65a53168dfd5d0c24087f2b12a291263d5842507417f", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "88e6f46c96dc34fd282754d444a820044a08371a15c13ca62d1bffc87f03a4bbcb9cd7b047ecbcbd60db7db3ebd6d8521a717fbf356e075a43639bff6c910fdd939c1f0f0d846db6d907ed6496df697e9413ea6a22541002ca8066e01db82754c5a37f6196dc34fd280654d27eea0801128115c6c171b794c5a37fd5d0c7", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "88e15f87352398ac5754dfe1e0dfd0cf7f02a472fdfab46e4d536a67011aed8f8e5cf51eddec6ae9cb266e5aa766b77f02fd1e2116083fdcd70f0d023637d2", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "88bf7ea5bfcffdc9a9cc28731eae9973fbfc9750bbfb21e1bd6cc7afc27a7fbfd977612b3fec190f07ddd80f0d023637", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "88edc06c96d07abe940b6a6a2254100225001b817ee09e53168dffcfd47f00a4e0ca5b3f4fd87f3751ed8b254f7e3f9a2437fb9360e1a2f79eefb76b55619291eaaf841f0f0d837196455892aed8e8313e94a47e561cc5804fbce36d3ccf6496df697e940b6a6a22541002ca806ae34fdc0094c5a37fe1dcce", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88f1e06c96df3dbf4a044a435d8a0801128066e019b817d4c5a37fd3d87f02a3e5d74bfd7def0648f2d54ebe30958cb59b507342ca2fd2de5367d36ffbaca3e02160830f0d830804df5892aed8e8313e94a47e561cc5802e882e3cdb5fcd6196dc34fd280654d27eea0801128115c6c3700053168dffe0d2cd", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "88f50f0d8375f0375f91497ca582211f6a1271d882a60b532acf7f6c96dd6d5f4a09e535112a080112820dc65eb8d854c5a37fd87f03a5968e17fc6dfc8499b1517bf78ffbbae79ac3d4de45ef468174bc3cf63d8bf394bab73e783fd05892aed8e8313e94a47e561cc5819085f0b8f37f6496e4593e94640a6a22541002ca8166e045704da98b46ffc3e5e0d7", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "8854012a0f0d03393630ce6c96df3dbf4a01d532db52820044a081702edc0814c5a37fdd7f03a440a3dd66a9b76ab2a20720b9ffb9ef53fba7a6a6b2e6db0a32f7ef8374fd5df3df64e083d55892aed8e8313e94a47e561cc5804dbadb2d85ef6496e4593e9413ca436cca08016540b571972e080a62d1bf6196dc34fd280654d27eea0801128115c6c3700253168dffebe6dd", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "88c3d36c96c361be940b2a65b68504008940b3700ddc69f53168dfe2e77f03a593776c3a3a337760e977359d0f8d17f87adda79f91158fd85ae9d7fd9b3f8d97dbedfef4410f0d830b420f5892aed8e8313e94a47e561cc5804dbadb2db4df6496e4593e9413ca436cca08016540b571972e34ea98b46fc2efe1dc", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "88c70f0d8365f75d5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559ef6c96dc34fd282754d444a820044a08371a0dc65e53168dffe77f03a334a1cfeb062bd833398184e3c3939f6df21369714a2e746361ebda49dd20d1ba36c907df5892aed8e8313e94a47e561cc5819085c105d67f6496e4593e94640a6a22541002ca806ee0017196d4c5a37fc7f4efe6", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "88ccdc6c96df3dbf4a044a435d8a0801128066e019b80654c5a37febf07f02a3068d9d91ad2eee1ec9307b7e9465c1d41e0c5bc0f7ebd77966efd3d3532092eda5a83f0f0d033331365892aed8e8313e94a47e561cc5804db82782273f6496df697e9413aa436cca080165403371a72e09f53168df6196dc34fd280654d27eea0801128115c6c3700ca98b46ff408721eaa8a4498f5788ea52d6b0e83772ffece7", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "885f88352398ac74acb37f0f0d8371d75f6c96e4593e9403ea681fa5040089410ae36ddc6c0a62d1bf52848fd24a8fc2c1588ba47e561cc5802203ee001f", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "88c10f0d8375e7df6c96d07abe940b4a681fa5040089403f702ddc6da53168dfc0c4c3bf", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "88c20f0d8379f7036c96c361be94081486d99410022504cdc035704da98b46ffc1c06496dc34fd281754d27eea0801128115c6c3700ca98b46ffc6c5", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88c40f0d83744e836c96df3dbf4a05d5340fd2820044a05db8015c138a62d1bfc3c2bfc7c6", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88c50f0d840804f35f6c96c361be940b4a6e2d6a0801128166e34cdc0054c5a37fc4c8c7c3", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88c60f0d8371f6456c96df697e940b6a681fa504008940b971b66e040a62d1bfc5c4c9c8", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88c70f0d840bed01af6c96c361be940b2a65b6850400894106e32f5c0baa62d1bfc6c5c2cac9", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "8858bbaec3771a4bf4a54759093d85fa52a3ac419272fd294da84ad617b8e83483497e94ace84ac49ca4eb003e94aec2ac49ca4eb003e94a47e561cc58015f87352398ac4c697f6495df3dbf4a05486bb141000d2800dc006e002a62d1bf6c95df3dbf4a05486bb141000d2800dc006e000a62d1bf4085aec1cd48ff86a8eb10649cbf4089f2b4b1ad495361888f1c7b2277223a32332c2272223a32342c2271223a302c2261223a33317d4089f2b4b1ac82d9dcb67f8a08170b8d2e2034bbcfff7f15a4a67f736bd5bf77fbb2fbbf9eba5f0cd5b3ef95121cdfb5d252facc0472bdf9e6f539de836196dc34fd280654d27eea0801128115c6c3700d298b46ffd20f0d023433", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88c6c5c4c3c27f021d7b2277223a31332c2272223a3133372c2271223a302c2261223a32337d7f028a08170b8d2e171d5db67f7f02a3b795e739f86f2f44bc9adcc5a3930023bd9a46c37ad3fec92a30db4fab07d346ecf820c1d50f0d023433", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88c9d4c7c6c57f011c7b2277223a32302c2272223a34332c2271223a302c2261223a33307d7f018908170b8daed89771df7f01a4cce6a7fdfbc5523a75c3c09d38d5dcf366c15bdcbd73cd7efb6c0776d859cbabb6ff6f41c4d80f0d84081965af5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88cdd8cbcac97f021c7b2277223a34302c2272223a33332c2271223a302c2261223a32327d7f028908170b8d2e102eebff7f02a69b87fbcdb6f6de5670affd8f06fddc70c22ff7b3b7bcadbba2cf4dfa78cfe9fdc9bb6fbe2d41c8dc0f0d8475f005ffc1", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88d05f87352398ac5754dfcfcecdc1c07f00a5166e7259a64ff7de1e918f90bfdd0fd1fa023fdb655b365b9ef02de3fec77f96096ac0883fcade0f0d023637c3", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88bf7ea5a13fbcd90f8fd283cbfd3a7e7effb6316cd17b27eb99ffdf0f79c9c708fa35ccaf1300e683cbdf0f0d023637", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88c00f0d846442103f6c96d07abe940b6a6a225410022502ddc65db80794c5a37fdde1e0dc", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88c10f0d85081b740cff6c96d07abe940b6a6a225410022502ddc65eb80654c5a37fdee2e1dd", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88d40f0d8465c75c7b6c96df3dbf4a002a693f750400894006e36ddc684a62d1bfdfe3e2de", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88c30f0d85085f6dd6bf6c96c361be94138a6a225410022500fdc683702253168dffe0e4e3df", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "8854012a0f0d033635395f89352398ac7958c43d5f6c96df3dbf4a044a435d8a0801128066e019b821298b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb7f07a4f581ea7c8baead04c8f6c6b424f9af7e7387f3bbbe7768d97715b29ee83d31dbaf3c08834087f2b12a291263d5842507417f5892aed8e8313e94a47e561cc5802e3207c4e03f6496dc34fd2810a9a07e941002ca8076e045700e298b46ff6196dc34fd280654d27eea0801128115c6c3700e298b46ffecd17b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "88ec0f0d8371f71c6c96df3dbf4a05d5340fd2820044a05cb8272e01c53168dfebeae76196dc34fd280654d27eea0801128115c6c3700fa98b46ffef", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "88ee0f0d8369b0076c96c361be94038a65b6850400894086e32e5c69b53168dfedbff0ec", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "88ef0f0d8465d699176c96d07abe94034a65b6a5040089403d7196ee36253168dfeec0f1ed", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88f00f0d83742fbd6c96df697e940b6a681fa504008940b971a6ee05953168dfefc1f2ee", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "88d30f0d840b2d36d76c96df3dbf4a3215340fd2820044a00371a7ae32f298b46ff0c2f3ef", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "88d85f8b1d75d0620d263d4c7441ea54919d29aee30c78f1e1794642c673f55c87a7409619085421621ea4d87a161d141fc2c4b0b216a4987423834d969758b3aec3771a4bf4a54759093d85fa52a3ac419272fd294da84ad617b8e83483497e94ace84ac49ca4eb003e94aec2ac49ca4eb003e7798624f6d5d4b27f6196dc34fd280654d27eea0801128115c6c3700f298b46ff408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "88db0f0d840bedb2ef6c96df697e940bea65b6a5040089403d71b0dc13aa62d1bf52848fd24a8f588ba47e561cc5802203ee001ff6ccc1", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "885f88352398ac74acb37f0f0d836de6856c96d07abe940b4a681fa5040089410ae019b8d3aa62d1bfc1cec3c0", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88bf0f0d8371f7596c96df697e941094d03f4a0801128266e09cb8d32a62d1bfc2cfc4c1", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "88c00f0d83744e336c96d07abe940854cb6d4a080112820dc086e042a62d1bffc3d0c5c2", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88c10f0d837042176c96df697e940b6a681fa5040089400ae041702053168dffc4c36496dc34fd281754d27eea0801128115c6c3700fa98b46ffd2c7", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88c30f0d8378006f6c96c361be940b2a65b685040089400ae360b82754c5a37fc6d3c8c5", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "88c40f0d8375f69f6c96e4593e94642a6a225410022502edc1377190298b46ffc7d4c9c6", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88c50f0d836de6c16c96e4593e94132a681fa504008940b3700d5c036a62d1bfc8d5cac7", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88c60f0d8369e7016c96c361be940bca681fa5040089403971b7ee05953168dfc9d6cbc8", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88e80f0d8465c702df6c96c361be9403ca65b6a5040089403f702f5c65b53168dfcad7ccc9", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "88e90f0d841381781f6c96c361be940054cb6d4a0801128115c6deb82794c5a37fcbd8cdca", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88c90f0d8379b6c36c96e4593e940b8a681fa50400894002e05fb820298b46ffcc6196dc34fd280654d27eea0801128115c6c3702053168dffcfcc", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "88cb0f0d8374020f6c96c361be940bca681fa5040089403d71b7ae01953168dfcebfd0cd", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88cc0f0d837822736c96df3dbf4a05d5340fd2820044a0417190dc0014c5a37fcfc0d1ce", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "88ee0f0d84105d781f6c96c361be941014cb6d0a0801128205c699b81694c5a37fd0c1d2cf", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "88ef0f0d840b8103ff6c96c361be9403ca65b6a50400894106e34ddc0014c5a37fd1ded3d0", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "88cf0f0d836c4d3d6c96df697e940b6a681fa504008940bb702fdc1094c5a37fd2dfd4d1", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88d00f0d8375c0036c96df697e940b6a681fa50400894002e005702ca98b46ffd3d2e0d5", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "88d10f0d83782d3d6c96df697e94034a6e2d6a080112806ee09bb81754c5a37fd4d36496dc34fd281754d27eea0801128115c6c3700ca98b46ffe2d7", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88f40f0d84132e3cf76c96df697e94036a65b6a504008940b971b7ae36e298b46fd6d56496dc34fd281754d27eea0801128115c6c3702053168dffc8d9", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88f60f0d84644dbaff6c96c361be940b6a65b6a504008941337041b8c854c5a37fd8e5dad7", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88f70f0d8465c0b6d76c96df697e940b6a681fa504008940b971b66e01a53168dfd9e6dbd8", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "88d70f0d83784e076c96df3dbf4a05d5340fd2820044a05cb816ee05f53168dfdae7dcd9", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "885f87352398ac5754df0f0d8465a700cf6c96df697e94036a65b6a504008940bf71966e32053168dfdcdbc5e9de", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88bf0f0d840bec881f6c96c361be941014cb6d0a0801128215c659b810298b46ffddeadfdc", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "88f55f91497ca582211f6a1271d882a60b532acf7f6c96dc34fd282754d444a820044a08371b7ee36e298b46fff45a839bd9ab7f35a3260b1abd5f6f5ae8b53fb8343659b43b839078b184fa738d0f576f69f267d5eaa726830f0d830b6f3f5892aed8e8313e94a47e561cc5819085f0b4107f6496e4593e94640a6a22541002ca8166e01eb806d4c5a37f6196dc34fd280654d27eea0801128115c6c3702da98b46ffe6f3f7", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "8854012ac86c96df3dbf4a044a435d8a0801128066e019b8cb4a62d1bf4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbc57f05a3ddd23e5ef9649c8ddb7cbc26cdefa8e768fc47e304baa54769aa75f4e5ef9cdaafc3070f0d82089a5892aed8e8313e94a47e561cc5804db8c89d7dbf6496df697e9413aa436cca0801654037700d5c640a62d1bfc4ec7b8b84842d695b05443c86aa6f4087f2b12a291263d5842507417f", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "88c5cf6c96df3dbf4a044a435d8a0801128066e00571b7d4c5a37fc47f04a47aef3e70dfc86cfcbf75eded65334fab7e5aaab5b8dd6f255d33e5e76d2813ff9b2f35070f0d033137385892aed8e8313e94a47e561cc5804db8cbcf32f76496df697e9413aa436cca080165403971a6ee05953168dfcaf2", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "88c95f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559ef6c96c361be94138a6a2254100225041b8d0ae01d53168dffc9d07f03a3b26619f210175fae4dffbe7dc2d1fa8cba26d95c992f993c2bdb2176518e4705e3841f0f0d8365a033c65892aed8e8313e94a47e561cc5819081f7dc71df6496df697e9413ea6a22541002ca810dc65fb801298b46ffcff7", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "88cec26c96dd6d5f4a09e535112a080112820dc086e32d298b46ffcdd47f02a4ff788123bcc2c550e675c9dba03ea6fd24d87d76eb8e4e7cfa7bb5f8f4bdbf7cfbf9020f0f0d8365d7da5892aed8e8313e94a47e561cc5819081f03cf39f6496df697e9413ea6a22541002ca807ee04571a1298b46ff6196dc34fd280654d27eea0801128115c6c3702e298b46ff408721eaa8a4498f5788ea52d6b0e83772ffcecd", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "88d4c86c96df3dbf4a09d53716b5040089410ae05fb82794c5a37fd37f04a5fdf2fffb04f92f4c7b23a7a340ff7bf8ecede5872ff2ea0cb84dd3c368d47b75666bcbd07f0f0d836990b95892aed8e8313e94a47e561cc5819085f0b4d0bf6496e4593e94640a6a22541002ca8166e01eb8cbca62d1bfc3c2ddd2", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88d8e2d0d6dd7f01a3f4fcd5819ed9e9c5e24b3a5934c8c3ebce6e15496edb71b9fbd67c7e99ca20bbe2a8600f0d023832d35892aed8e8313e94a47e561cc5804db8278220ff6496df697e9413aa436cca080165403371a72e32ea98b46fc6c5", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88dbe56c96df3dbf4a044a435d8a0801128066e019b816d4c5a37fdae17f02a4f4c8727bd49fcf6e6cc1dafc6d739deab3bf81dcbed9d92589c3bf8ef972d787238ea20f0f0d8213c15892aed8e8313e94a47e561cc5804db82782277f6496df697e9413aa436cca080165403371a72e34ca98b46fcac9d9d8", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88dfd36c96dd6d5f4a09e535112a080112820dc03b71a794c5a37fdee57f02a324998eed52b9ba3c3360e08b5eadefdaf9f5f5205ac9d77239f8b5eaf057d326be4f410f0d840bcdbc1fdb5892aed8e8313e94a47e561cc5819081c79f701f6496df697e9413ea6a22541002ca8066e01db816d4c5a37fe4cd", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "88e3ea6c96dd6d5f4a09e535112a080112820dc13d704253168dffe2e97f02a3d043f404bea986966ef2dbdf39f03f6f19accbd7f3abdca892a7e7e19a8f4e6bc0e0200f0d033638365892aed8e8313e94a47e561cc5819081c759135f6496df697e9413ea6a22541002ca8015c681700153168dff6196dc34fd280654d27eea0801128115c6c3702ea98b46ffd2e2e1", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "88e80f0d84740f09aff26c96dd6d5f4a09e535112a080112816ae32ddc0814c5a37fe77f03a3e0e5eab2ec2bb461d0db1e3bf3bbb4983d77379389e6bb21993ce1c8d77c9959dd29e0e35892aed8e8313e94a47e561cc58190842ebecb7f6496df697e9413ea6a22541002ca8172e34cdc640a62d1bfedd6f1e6", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88ec0f0d8371f6d95f951d75d0620d263d4c7959139c9d7c0fb9569681a27f6c96d07abe9413ea6a225410022502f5c6dcb8d814c5a37fec7f03a47b6eafccd958ccde43e9fdc4ced2653e97b39cf3e6f47bfc846de572ae6fcfb7269c907fe85890aed8e8313e94a47e561cc5804e0196456496df697e94038a693f7504008940b37020b811298b46ff6196dc34fd280654d27eea0801128115c6c3704053168dffdc5a839bd9abed", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88f30f0d8371f6d9c4c3f1c2ec5890aed8e8313e94a47e561cc5804e019643c16196dc34fd280654d27eea0801128115c6c3704153168dffdfc0ef", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "88f5e96c96df697e94640a6a225410022502edc69bb827d4c5a37ff4c17f06a420d16774d1db432f5fc5370cdfed179c6bc73c3cbb7e127bda05e2ad1d26d0f71bcfbd070f0d840b6e3cdf5892aed8e8313e94a47e561cc5819089f7c2107f6496df3dbf4a321535112a08016540bf700cdc0814c5a37fc5e3f3f2", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "8854012a0f0d830b6f87ee6c96df3dbf4a080a6e2d6a080112800dc08ae32da98b46ff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb7f04a6c0ffe76cfd890eb48f472cdfefbd1e77eff53e9d7a0be38767eadd7b30fcffba5fcda3c7583f4087f2b12a291263d5842507417f5892aed8e8313e94a47e561cc5804f3aeb8265bf6496e4593e940094d444a820059502d5c0b7704d298b46ff6196dc34fd280654d27eea0801128115c6c3704fa98b46ffebcc7b8b84842d695b05443c86aa6f", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_27.json b/http/http-client/src/test/resources/hpack-test-case/story_27.json new file mode 100644 index 0000000000..8c4215005f --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_27.json @@ -0,0 +1,10328 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264026196dc34fd280654d27eea0801128166e341b811298b46ff4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e044a62d1bfed4ac699e063ed490f48cd540bcb4189d6c5c87a7f0f1f919d29aee30c78f1e17968313ad8b90f4b1f5885aec3771a4b4089f2b20b6772c8b47ebf94f1e3c05f7d7968313ad8bd36c8bfa1ce73ae43d37b8b84842d695b05443c86aa6f5a839bd9ab0f0d023230408721eaa8a4498f57842507417f5f92497ca589d34d1f6a1271d882a60e1bf0acf7", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "886196dc34fd280654d27eea0801128166e341b81654c5a37fc56c96dc34fd280654d27eea0801128005c037700153168dff52848fd24a8fc4c3c5408bf2b4b4189d6c59091a4c4f013158a1a8eb2127b0bf4a547588324e5fa529b5095ac2f71d0690692fd2948fcac398b0034085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5501307cecc7bf7eb602b854b02e2fe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb26846e954ffe7f7f4a63dfbf5b015c2a58012fe895997a4c35fd0e739d7a8a953fae639ce7df60e594c4dc5b3b96c602b880b880a7fec9a11ba553ff9fdff7688e7bf73015c405c40798624f6d5d4b27f7f0b88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "886196dc34fd280654d27eea0801128166e341b816d4c5a37fd15895aec3771a4bf4a54759093d85fa5291f9587316007fcfcdc15f911d75d0620d263d4c795ba0fb8d04b0d5a7cf", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "886196e4593e94642a6a225410022500fdc6c1704253168dffd46c96c361be94038a65b68504008940bf702ddc69c53168dfccd2d17f1494f1e3c09b5e5a0c4eb62f4db22fe8739ceb90f4ffcc588ca47e561cc58190b6cb800001cb5f87352398ac5754df558513ac81b67f7cebc7bf7eb602b854b1a12fe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb2634292a9ffcfefe94c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd931a14954ffe7f7cac9c80f0d8465b0805f6496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "886196df3dbf4a002a693f750400894035704cdc65e53168dfdc6c96df697e94038a681d8a0801128266e34f5c03ca62d1bfd40f0d84105e641f7f0694f1e3c05a6d7968313ad8bd36c8bfa1ce73ae43d3c1c5c45585101c136eff7cebc7bf7eb602b854b1a717f44accbd36c8bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd931a14954ffe7f7f4a63dfbf5b015c2a58fafe895997a4c35fd0e739d7a8a953fae639ce7df60e594c4dc5b3b96c602b880b880a7fec98d0a4aa7ff3fbfd0ce", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88cde0c9d7dddc7f0194f1e3c05e757968313ad8bd36c8bfa1ce73ae43d3d7e0d5dbd37cecc7bf7eb602b854b1a697f44accbd36c8bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbfa531efdfad80ae152c0097f44accbd261afe8739cebd454a9fd731ce73efb072ca626e2d9dcb63015c405c4053ff64d08dd2a9ffcfeffd2d1d00f0d8465b0805fc50f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e05b53168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "886196dc34fd280654d27eea0801128166e341b81714c5a37fe30f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028cb6da9210208aa287d86496dc34fd280654d27eea0801128166e341b81754c5a37f5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d03333237dd408b4d8327535532c848d36a3f8b96b2288324aa26c193a964e4e2d2", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "886196dc34fd280654d27eea0801128166e09eb82654c5a37f7f29ff27acf4189eac2cb07f33a535dc618ad9ad7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70298b571fe76c96dc34fd280654d27eea0801128166e001702fa98b46ffe17b9384842d695b05443c86aa6fae082d8b43316a4fe75889a47e561cc58197000f5f92497ca58ae819aafb50938ec415305a99567b55033737330f0d8408422701dc7687877ee6195c4b83", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88caef5894a8eb10649cbf4a54759093d85fa52bb0ddc692ffe40f0d023433eb5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "886196dc34fd280654d27eea0801128166e341b817d4c5a37ff2dbe9efee7f1094f1e3c05e5e5a0c4eb62f4db22fe8739ceb90f4ffe9f2e7e6e57cecc7bf7eb602b854b1a797f44accbd36c8bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbfa531efdfad80ae152c0097f44accbd261afe8739cebd454a9fd731ce73efb072ca626e2d9dcb63015c405c4053ff64d08dd2a9ffcfeffe4e3e20f0d8465b0805fd70f28c096890a9291259281d53405a96b51f6a17cd66b0a8839164fa50025b28ea58400b2a059b8d06e05f53168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "886196dc34fd280654d27eea0801128166e341b820298b46ff5f88352398ac74acb37f0f0d836c0017e47f0cff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa50401094082e320b80794e1bef76c96d07abe94640a436cca0801028072e01db8cb2a62d1bf52848fd24a8f558469b79a174085f2b10649cb9fc7937a92d87a54ae73a4e419272b6102f2d06275b17191a5fd0e739d721e9f408af2b10649cab5073f5b6ba1c7937a92d87a54ae73a4e419272b6102f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad840bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 11, + "wire": "88c8c70f0d8313cd3fedc6c56496d07abe94640a681fa50401094082e361b8cbea70df7b6c96d07abe94640a436cca0801028072e01db8c814c5a37fc4558479e038cf7f049fc7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb405e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 12, + "wire": "88cecd0f0d8365b659408721eaa8a4498f5788ea52d6b0e83772ffcdcc6496df3dbf4a09d535112a0802128215c6437190a9c37def6c96d07abe94640a436cca0801028072e01db82754c5a37fcb5585700fb4d3ff7f059fc7937a92d87a54ae73a4e419272b6c817968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b6c817968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb205e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 13, + "wire": "88d5d40f0d83782e37c4d3d26496dd6d5f4a019532db42820084a01db8cb570215386fbd6c96df697e940814d27eea08007d4102e05bb8cb4a62d1bfd155830b2c8b7f049fc7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cac89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 14, + "wire": "88dbda0f0d840b80681fcad9d8d06c96e4593e940b6a6e2d6a080102817ee34cdc644a62d1bfd65585081a75c7bf7f039fc7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 15, + "wire": "88e0df0f0d840b8f05efcfdeddd56c96e4593e940b6a6e2d6a080102817ee34cdc0bea62d1bfdbc2cccbca", + "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)" + } + ] + }, + { + "seqno": 16, + "wire": "88e1e00f0d85136f3ccbdfd0dfde6496d07abe94640a681fa5040109403f702d5c1014e1bef76c96d07abe94640a436cca0801028072e01db8cb4a62d1bfdd558365f6417f059fc7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a77f05a2c7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2d2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 17, + "wire": "88e7e60f0d840b6d859fd6e5e46496d07abe94640a681fa5040109403f71a76e32d29c37de6c96d07abe94038a65b6a50400854086e08571b7d4c5a37fe355837dc69b7f049fc7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad804bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 18, + "wire": "88edeb0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028cbc0524204315450f4085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b820a98b46ff5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436eb408b4d8327535532c848d36a3f8b96b2288324aa26c193a9647b8b84842d695b05443c86aa6f7f23842507417f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "886196dc34fd280654d27eea0801128166e341b820a98b46ff5f88352398ac74acb37f0f0d8375e75ee64003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627f6496e4593e941014cb6d0a0802128115c133702f29c37def6c96d07abe94132a65b6a504003ca05fb816ee01a53168df52848fd24a8f5584682eb4e77f119fc7937a92d87a54ae73a4e419272842d2f2d06275b17a6d917f439ce75c87a77f11a2c7937a92d87a54ae73a4e419272842d2f2d06275b17a6d917f439ce75c87a6e3ccff7cae0ae152b9ce9390649ca10b4bcb4189d6c5e9b645fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 20, + "wire": "88c8c65894a8eb10649cbf4a54759093d85fa52bb0ddc692ffd00f0d023433cb5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88cac90f0d8365965ff1c8c76496dc34fd2800a9a889504010940b571a7ee36d29c37def6c96d07abe940054d444a820044a019b8d82e32253168dffc6558475f7402f7f069fc7937a92d87a54ae73a4e419272be012f2d06275b178e50afe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272be012f2d06275b178e50afe8739ceb90f4dc7997cae0ae152b9ce9390649caf804bcb4189d6c5e3942bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 22, + "wire": "88d0ce6c96c361be94038a65b68504008940bf702ddc69c53168dfcbd45a839bd9ab4089f2b20b6772c8b47ebf94f1e3c05a6d7968313ad8bd36c8bfa1ce73ae43d3408bf2b4b4189d6c59091a4c4f01315885aec3771a4bdc5f96497ca58e83ee3412c3569fb50938ec415305a99567bf5501307cebc7bf7eb602b854b0025fd12b32f4db22fe8739cebd454a9fd731ce73efb072ca626e2d9dcb63015c405c4053ff64d08dd2a9ffcfefe94c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fb7688e7bf73015c405c40798624f6d5d4b27f7f1d88ea52d6b0e83772ff0f0d8465b0805f6496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c096890a9291259281d53405a96b51f6a17cd66b0a8839164fa50025b28ea58400b2a059b8d06e05f53168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "886196dc34fd280654d27eea0801128166e341b821298b46ffdc0f0d8365a033c0dbda6496d07abe94640a681fa50401094086e00370025386fbdf6c96df3dbf4a05c53716b504008140bb702fdc69d53168dfd955850b4e3826bf7f119fc7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a77f11a2c7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2f2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 24, + "wire": "88c4e20f0d8364017bc6e1e06496d07abe94640a681fa50401094086e32ddc038a70df7b6c96df3dbf4a05c53716b504008140bb702fdc642a62d1bfdf558569f79c6c1f7f049fc7937a92d87a54ae73a4e419272b607d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b607d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 25, + "wire": "88cae80f0d8365a7d9cce7e6c96c96df3dbf4a05c53716b504008140bb702fdc69f53168dfe455850bcd3a173f7f039fc7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 26, + "wire": "88cfed0f0d840be071cfd1ecebc86c96df3dbf4a05c53716b504008140bb702fdc65f53168dfe9c77f029fc7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a77f02a2c7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2d2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 27, + "wire": "88d3f10f0d840b4dbcefd5f0efcc6c96e4593e940b6a6e2d6a080102817ee34d5c032a62d1bfedcb7f029fc7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9f7f02a1c7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad844bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 28, + "wire": "88d75f88352398ac74acb37f0f0d840b8db41fda4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109403f71b0dc65f5386fbd6c96e4593e940b6a6e2d6a080102817ee34cdc6db53168df52848fd24a8f558471a0b4dfdad9d8", + "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)" + } + ] + }, + { + "seqno": 29, + "wire": "88dec40f0d840bae38ffe0c3c2d76c96e4593e940b6a6e2d6a080102817ee34cdc69e53168dfc0558569f780e83f7f0a9fc7937a92d87a54ae73a4e419272b6cb8bcb4189d6c5c64697f439ce75c87a77f0aa2c7937a92d87a54ae73a4e419272b6cb8bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2e2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 30, + "wire": "88e3c90f0d840ba003ffe5c8c7dc6c96e4593e940b6a6e2d6a080102817ee34cdc680a62d1bfc5c27f029fc7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4f7f02a1c7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 31, + "wire": "88e7cd0f0d84084007c1e9cccb6496d07abe94640a681fa5040109403f71b05c69f5386fbd6c96d07abe94640a436cca0801028072e01db8c854c5a37fca5585081a75c67f7f049fc7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 32, + "wire": "88edd30f0d840882169befd2d16496d07abe94640a681fa5040109403f702d5c1094e1bef76c96e4593e940b6a6e2d6a080102817ee34cdc0bea62d1bfd0c37f039fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 33, + "wire": "886196dc34fd280654d27eea0801128166e341b82654c5a37fd86c96c361be94038a65b68504008940bf702ddc69c53168dfd57b8b84842d695b05443c86aa6f5a839bd9ab4089f2b20b6772c8b47ebf94f1e3c040daf2d06275b17a6d917f439ce75c87a7408bf2b4b4189d6c59091a4c4f01315885aec3771a4b4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5501307cecc7bf7eb602b854b00f2fe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb26846e954ffe7f7f4a63dfbf5b015c2a58012fe895997a4c35fd0e739d7a8a953fae639ce7df60e594c4dc5b3b96c602b880b880a7fec9a11ba553ff9fdff7688e7bf73015c405c40798624f6d5d4b27f408721eaa8a4498f5788ea52d6b0e83772ff0f0d8465b0805f6496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e09953168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "886196dc34fd280654d27eea0801128166e341b82694c5a37fe70f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028c89e524209c8aa287c76496dc34fd280654d27eea0801128166e341b826d4c5a37f5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436e6408b4d8327535532c848d36a3f8b96b2288324aa26c193a964cf7f05842507417f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88c4ee0f0d836d9745c6edec6496dd6d5f4a09a532db42820084a01bb8066e01b5386fbd6c96dc34fd28102996da1410020502f5c6deb800a98b46ffeb5585085975f77f7f1a9fc7937a92d87a54ae73a4e419272b41757968313ad8b8c8d2fe8739ceb90f4f7f1aa1c7937a92d87a54ae73a4e419272b41757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad05d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 36, + "wire": "88caf35894a8eb10649cbf4a54759093d85fa52bb0ddc692ffd30f0d023433c65f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "886196dc34fd280654d27eea0801128166e341b826d4c5a37f5f88352398ac74acb37f0f0d8408020745d04003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109403f702cdc6c0a70df7b6c96e4593e940b6a6e2d6a080102817ee34cdc65953168df52848fd24a8f558565f7c226bf7f0b9fc7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9f7f0ba1c7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad804bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 38, + "wire": "88c8c6e5c2e4e37f2394f1e3c0596d7968313ad8bd36c8bfa1ce73ae43d3e2e1e0df5501337cecc7bf7eb602b854b19697f44accbd36c8bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbfa531efdfad80ae152c0097f44accbd261afe8739cebd454a9fd731ce73efb072ca626e2d9dcb63015c405c4053ff64d08dd2a9ffcfeffdedddc0f0d8465b0805fdb0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e09b53168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "886196dc34fd280654d27eea0801128166e341b82714c5a37fca0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f7f1b8a028cb6f292104f455143e46496dc34fd280654d27eea0801128166e341b82754c5a37fda0f0d023436c8d9ead8d7", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88c0ccd0e50f0d023433d8cf", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88c0ccd0e50f0d023433d8cf", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "886196dc34fd280654d27eea0801128166e341b82754c5a37fcdd1e60f0d023433d9d0", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "88bece0f0d840b217842e0cdcc6496d07abe94640a681fa5040109403f702cdc0bea70df7b6c96e4593e940b6a6e2d6a080102817ee34cdc680a62d1bfcb558565f7c226ff7f0b9fc7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4f7f0ba1c7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 44, + "wire": "88c4d3f2cff1f07f0b94f1e3c05f797968313ad8bd36c8bfa1ce73ae43d3efeeedeccac9e9e8e70f0d8465b0805fe60f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e09d53168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "886196dc34fd280654d27eea0801128166e341b82794c5a37fd50f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f7f098a028cb8e292119722a8a1ef6496dc34fd280654d27eea0801128166e341b827d4c5a37fe50f0d023436d3e4f5e3e2", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "886196dc34fd280654d27eea0801128166e341b827d4c5a37fd8dcf10f0d023433e4db", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88bed90f0d850b2ebae3bfebd8d76496d07abe94640a681fa5040109403f702cdc034a70df7b6c96e4593e940b6a6e2d6a080102817ee34cdc69e53168dfd655857db7dc79ef7f099fc7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9f7f09a1c7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad844bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 48, + "wire": "886196dc34fd280654d27eea0801128166e341b8c814c5a37fdf6c96c361be94038a65b68504008940bf702ddc69c53168dfdc7b8b84842d695b05443c86aa6f5a839bd9ab7f0d93f1e3c09a5e5a0c4eb62f1ca15fd0e739d721e9408bf2b4b4189d6c59091a4c4f01315885aec3771a4b4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5501317cb5c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbf7688e7bf73015c405c40798624f6d5d4b27f408721eaa8a4498f5788ea52d6b0e83772ff0f0d8465b0805f6496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e32053168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "88ccee0f0d837dd6dbbfedec6496d07abe94640a681fa504010940b3704edc682a70df7b6c96d07abe94034a6a225410020504cdc086e05e53168dffeb558575e65d71ef7f139fc7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4f7f13a1c7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 50, + "wire": "88d2f40f0d8378017bc5f3f2c36c96d07abe94034a6a225410020504cdc086e05c53168dfff0558575e65d71df7f039fc7937a92d87a54ae73a4e419272b620af2d06275b17191a5fd0e739d721e9f7f03a1c7937a92d87a54ae73a4e419272b620af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad882bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 51, + "wire": "88d75f88352398ac74acb37f0f0d836db03fcb4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627fcb6c96d07abe94034a6a225410020504cdc086e05f53168dff52848fd24a8f558579a7dd107f7f079fc7937a92d87a54ae73a4e419272b61757968313ad8b8c8d2fe8739ceb90f4f7f07a1c7937a92d87a54ae73a4e419272b61757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 52, + "wire": "88e0c60f0d84134269afd3c5c4d1c3c25585799109967f7f029fc7937a92d87a54ae73a4e419272b60657968313ad8b8c8d2fe8739ceb90f4f7f02a1c7937a92d87a54ae73a4e419272b60657968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad8195e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 53, + "wire": "88e4ca0f0d840b6e3effd7c9c86496d07abe94640a681fa5040109408ae34fdc69c5386fbd6c96df3dbf4a05c53716b504008140bb702fdc6da53168dfc855850bcd3a26bf7f049fc7937a92d87a54ae73a4e419272b6cb6bcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cb6bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2daf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 54, + "wire": "88ead00f0d8413806c3fddcfcedb6c96df3dbf4a05c53716b504008140bf700e5c0094c5a37fcdd57f029fc7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9f7f02a1c7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad802bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 55, + "wire": "88eed40f0d840b22719fe1d3d26496d07abe94640a681fa5040109408ae32f5c03ca70df7b6c96df3dbf4a05c53716b504008140bb702fdc642a62d1bfd25584105c081e7f049fc7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 56, + "wire": "88f4da0f0d840bec89afe7d9d86496dd6d5f4a019532db42820084a085704cdc13aa70df7b6c96df3dbf4a05c53716b504008140bb702fdc69f53168dfd85585640175917f7f049fc7937a92d87a54ae73a4e419272b6cbebcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cbebcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2faf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 57, + "wire": "886196dc34fd280654d27eea0801128166e341b8c814c5a37fe10f0d84105b759feee0df6496d07abe94640a681fa504010940b3704edc684a70df7b6c96df3dbf4a05c53716b504008140bb702fdc69d53168dfdf55840b4e34d77f059fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f05a1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 58, + "wire": "88c4e70f0d84101d641f408721eaa8a4498f5788ea52d6b0e83772ffe7e6c46c96e4593e940b6a6e2d6a080102817ee34d5c032a62d1bfe55585640179f07f7f049fc7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 59, + "wire": "88caed0f0d84644f85cfc3ecebd66c96df3dbf4a05c53716b504008140bb702fdc65f53168dfea5585136175e6ff7f039fc7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 60, + "wire": "88cf5f88352398ac74acb37f0f0d84138dbad7c94003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5892a47e561cc58190b6cb800001f55db1d0627fd16c96e4593e940b6a6e2d6a080102817ee34cdc6db53168df52848fd24a8f5585799109917f7f079fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f07a1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 61, + "wire": "88d8c60f0d8413aeb6ffd1c5c46496d07abe94640a681fa5040109410ae01cb82654e1bef76c96e4593e940b6a6e2d6a080102817ee34cdc69e53168dfc45585640179e67fd1d0cf", + "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)" + } + ] + }, + { + "seqno": 62, + "wire": "88dbc90f0d84085a03ffd4c8c76496d07abe94640a681fa5040109408ae32f5c0814e1bef76c96d07abe94640a436cca0801028072e01db8c854c5a37fc7c67f069fc7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 63, + "wire": "88e0ce0f0d84138d36cfd9cdcc6496dd6d5f4a09a532db42820084a01ab8db970425386fbd6c96d07abe94640a436cca0801028072e01db8cb2a62d1bfcc5583640dbdd4d3d2", + "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)" + } + ] + }, + { + "seqno": 64, + "wire": "88e3d10f0d84132113dfdcd0cfc86c96e4593e940b6a6e2d6a080102817ee34cdc65953168dfce5585640179d77f7f069fc7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a77f06a2c7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2d2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 65, + "wire": "88e8d60f0d8413c275bfe1d5d4cd6c96e4593e940b6a6e2d6a080102817ee34cdc680a62d1bfd35585640179e0ff7f039fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 66, + "wire": "88eddb0f0d84138271dfe6dad9d26c96e4593e940b6a6e2d6a080102817ee34cdc0bea62d1bfd85585640179d73f7f039fc7937a92d87a54ae73a4e419272b61697968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b61697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 67, + "wire": "886196dc34fd280654d27eea0801128166e341b8c854c5a37fe00f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028cb8fa92104cc551434085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8c894c5a37f5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436e1408b4d8327535532c848d36a3f8b96b2288324aa26c193a9647b8b84842d695b05443c86aa6f7f33842507417f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88c6e85894a8eb10649cbf4a54759093d85fa52bb0ddc692ffc50f0d023433c05f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88c8eabfc60f0d023433c1be", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "88c8eabfc60f0d023433c1be", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "886196e4593e94642a6a225410022500fdc643702253168dffeb6c96df697e94038a681d8a0801128266e34f5c03aa62d1bfe9c45a839bd9ab4089f2b20b6772c8b47ebf94f1e3c3ee2f2d06275b17a6d917f439ce75c87a7f408bf2b4b4189d6c59091a4c4f0131588ba47e561cc5802203ee001fcc5f91352398ac77aa45e9312c3a0f2a57310f57558413ad08407cebc7bf7eb602b854b02dafe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb2634292a9ffcfefe94c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd931a14954ffe7f77688e7bf73015c405c40798624f6d5d4b27f7f0d88ea52d6b0e83772ff0f0d8371c6816496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e32053168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "886196dc34fd280654d27eea0801128166e341b8cb2a62d1bf4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfcb52848fd24a8fd2cb7f0b93f1e3c057968313ad8bd36c8bfa1ce73ae43d3fca5885aec3771a4bd85f92497ca589d34d1f6a1271d882a60b532acf7f5501307cebc7bf7eb602b854b0225fd12b32f4db22fe8739cebd454a9fd731ce73efb072ca626e2d9dcb63015c405c4053ff64d08dd2a9ffcfefe94c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbc9c8c70f0d8371c681c60f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e32ca98b46ffb52b1a67818fb5243d2335502f2d06275b1721e9f", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "886196dc34fd280654d27eea0801128166e341b8cb4a62d1bf5f88352398ac74acb37f0f0d840be169afc9c65892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae32f5c03ea70df7b6c96d07abe94640a436cca0801028072e01db82754c5a37fc85585640179d17f7f279fc7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4f7f27a1c7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 74, + "wire": "88c6c50f0d841341083fd0cdc4c36c96d07abe94640a436cca0801028072e01db80694c5a37fcd558579a03417fff0efee", + "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)" + } + ] + }, + { + "seqno": 75, + "wire": "88c8c70f0d84644d01cfd2cfc66496d07abe94640a681fa504010940bd71a66e01d5386fbd6c96d07abe94640a436cca0801028072e01db81654c5a37fd055850b8e34d87f7f069fc7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 76, + "wire": "88cecd0f0d841000dbffd8d5cccb6c96d07abe94640a436cca0801028072e01db80754c5a37fd5558565e13ce3bf7f039fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 77, + "wire": "88d3d20f0d84132cb22fdddad16496d07abe94640a681fa5040109408ae341b8db6a70df7b6c96d07abe94640a436cca0801028072e01db81754c5a37fdb558471e65c077f049fc7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 78, + "wire": "88d9d80f0d840bcdb4cfe3e0d76496d07abe94640a681fa50401094086e09ab8d3ca70df7b6c96d07abe94640a436cca0801028072e01db80714c5a37fe1558569b79b659f7f049fc7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2f2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 79, + "wire": "88dfde0f0d840b6cbeffe9e6dd6496dd6d5f4a320535112a080212800dc69eb81714e1bef76c96e4593e94642a681d8a0801028176e34edc0854c5a37fe75585684d3cdbdf7f049fc7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cac89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 80, + "wire": "88e5e40f0d8413eebecfefece36496df697e940b8a436cca0802128215c65ab81754e1bef76c96d07abe940baa681fa5040081410ae001719694c5a37feddd7f039fc7937a92d87a54ae73a4e419272b400af2d06275b17191a5fd0e739d721e9f7f03a1c7937a92d87a54ae73a4e419272b400af2d06275b17191a5fd0e739d721e9b8f077cad0ae152b9ce9390649cad002bcb4189d6c5c64697f439ce75c87a6e3c153fa476b4d23025dd5f76f86ee7c0fff7", + "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)" + } + ] + }, + { + "seqno": 81, + "wire": "88eae90f0d840b2dba1f408721eaa8a4498f5788ea52d6b0e83772ff4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfea6496d07abe94640a681fa50401094086e05cb8cb8a70df7bdc52848fd24a8f558575e642f3dfe9e8e7", + "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)" + } + ] + }, + { + "seqno": 82, + "wire": "88efee0f0d840bc169ffc2c1ed6496dd6d5f4a044a65b6a504010941337022b8cb4a70df7b6c96d07abe940baa681fa50400814106e36fdc0b8a62d1bfc155857db65971af7f099fc7937a92d87a54ae73a4e419272b41697968313ad8b8c8d2fe8739ceb90f4f7f09a1c7937a92d87a54ae73a4e419272b41697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad05a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 83, + "wire": "886196dc34fd280654d27eea0801128166e341b8cb4a62d1bf5f88352398ac74acb37f0f0d840b6d019fcac95892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae32f5c03ea70df7b6c96d07abe94640a436cca0801028072e01db80654c5a37fca558565e784d83fedeceb", + "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)" + } + ] + }, + { + "seqno": 84, + "wire": "88c3c20f0d840b4ebee7cecdc16496d07abe94640a681fa5040109410ae01cb82694e1bef76c96d07abe940baa681fa50400814106e36fdc6de53168dfcd558464400bc07f0a9fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f0aa1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 85, + "wire": "88c9c80f0d840bce841fd4d3c7c66c96d07abe94640a436cca0801028072e01db82694c5a37fd2558579a03417ff7f039fc7937a92d87a54ae73a4e419272b6c857968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b6c857968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb215e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 86, + "wire": "88cecd0f0d84644db6dfd9d8cc6496dd6d5f4a05f532db52820084a05bb800dc03ca70df7b6c96d07abe940baa681fa5040081410ae001702ca98b46ffd855846de75a0f7f049fc7937a92d87a54ae73a4e419272b4112f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b4112f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad044bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 87, + "wire": "88d4d30f0d840b2e89cfdfded26496d07abe94640a681fa5040109408ae32f5c0814e1bef76c96d07abe940baa681fa50400814106e36fdc134a62d1bfdec9c8c7c6", + "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)" + } + ] + }, + { + "seqno": 88, + "wire": "88d6d50f0d8413ae380fe1e0d46496d07abe94640a681fa5040109410ae01cb8cb8a70df7b6c96d07abe940baa681fa50400814106e36fdc69d53168dfe0d07f059fc7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 89, + "wire": "88dbda0f0d840bedb4dfe6e5d9d86c96d07abe940baa681fa50400814106e36fdc640a62d1bfe4cf7f029fc7937a92d87a54ae73a4e419272b61757968313ad8b8c8d2fe8739ceb90f4f7f02a1c7937a92d87a54ae73a4e419272b61757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 90, + "wire": "88dfde0f0d84640d85efeae9dd6496d07abe94640a681fa504010940b9704f5c032a70df7b6c96e4593e94642a681d8a0801028176e34edc038a62d1bfe9558469f71e6f7f049fc7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 91, + "wire": "88e5ef0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028c840a4846598aa2874085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8cb6a62d1bf5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436f1408b4d8327535532c848d36a3f8b96b2288324aa26c193a9647b8b84842d695b05443c86aa6f408721eaa8a4498f57842507417f5f911d75d0620d263d4c795ba0fb8d04b0d5a7", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "886196dc34fd280654d27eea0801128166e341b8cb6a62d1bf4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf5894a8eb10649cbf4a54759093d85fa52bb0ddc692ffc70f0d023433c25f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "886196dc34fd280654d27eea0801128166e341b8cbca62d1bfc10f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f7f0b8a028cb4252423228aa287c5ca6496dc34fd280654d27eea0801128166e341b8cbea62d1bfc952848fd24a8f7f0a894192551360c9d4b27f0f0d023433c3", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "886196dc34fd280654d27eea0801128166e341b8cbea62d1bfc66c96df697e94038a681d8a0801128266e34f5c03aa62d1bfc1cb5a839bd9ab4089f2b20b6772c8b47ebf93f1e3c3215e5a0c4eb62f1ca15fd0e739d721e9408bf2b4b4189d6c59091a4c4f01315885aec3771a4bd35f92497ca589d34d1f6a1271d882a60b532acf7f5501337cb5c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbf7688e7bf73015c405c40798624f6d5d4b27f7f1488ea52d6b0e83772ff0f0d8371c6816496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e32fa98b46ffb52b1a67818fb5243d2335502f2d06275b1721e9f", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "886196dc34fd280654d27eea0801128166e341b8d014c5a37fd35895aec3771a4bf4a54759093d85fa5291f9587316007fd8d7c2d6ca", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "886196dc34fd280654d27eea0801128166e341b8d054c5a37fd50f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f7f128a028cb62524205f8aa287de6496dc34fd280654d27eea0801128166e341b8d094c5a37fdd0f0d023436d1dcdbdad9", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88768c86b19272ad78fe8e92b015c30f28d73535c03ffcd05ffa0b2d85f6c01005c082271c7de65a65c7a21d62080311aa4ffcfb52f9e919aa817496c190b5257a8a9fb53079acd615106f9edfa50025b40fd2c20059502cdc68371a0a98b46ffb5358d33c0c24682f7f19c7bdae0fe6f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a97786e53869c8a6be1b54c9a77a97f0685376f854d7b70297b568534c3c54d5bef29a756452feed6a5ed5b7f96495dc34fd28e29a07e940befb6a0457000b800298b46f5892ace84ac49ca4eb003e94aec2ac49ca4eb003e3d90f0d023433c4de", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88c4dbdae30f0d023433ded9", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "886196dc34fd280654d27eea0801128166e341b8d34a62d1bfdcd3d6e0d27f1294f1e3c36e2f2d06275b178e50afe8739ceb90f4ffd1d0e5cf550130cecdcccb0f0d8371c681ca0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e34d298b46ffb52b1a67818fb5243d2335502f2d06275b1721e9f", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88c05f88352398ac74acb37f0f0d8313cc83ccdf5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109403b71b05c0b8a70df7b6c96d07abe940054d27eea080102806ee341b820a98b46ffdc558368007f7f309fc7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9f7f30a1c7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad802bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 101, + "wire": "88c8c50f0d8369e79ad3e6c46496d07abe94640a681fa5040109403b71a6ae09b5386fbd6c96d07abe940054d27eea080102806ee341b8d854c5a37fe255850b6f85a77f7f049fc7937a92d87a54ae73a4e419272b6202f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b6202f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad880bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 102, + "wire": "88cecb0f0d8365b0b3d9ecca6496d07abe94640a681fa5040109403b71a7ee32da9c37de6c96d07abe940054d27eea080102806ee341b81794c5a37fe855836801077f049fc7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 103, + "wire": "88d4d10f0d8371e7dfdff2d06496d07abe94640a681fa5040109403b71a7ee01e5386fbd6c96d07abe940054d27eea080102806ee341b821298b46ffee55851322782fbd7f049fc7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 104, + "wire": "88dad70f0d8369c7dbe57f1eff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd76496df3dbf4a0195349fba820084a099b8d3f704d29c37de6c96d07abe940054d27eea080102806ee341b8cbea62d1bff57f04a0d19376e525b0f4a95ce749c8324e56c2d2f2d06275b17191a5fd0e739d721e9f7f04a2d19376e525b0f4a95ce749c8324e56c2d2f2d06275b17191a5fd0e739d721e9b8f337cae0ae152b9ce9390649cad85a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 105, + "wire": "88e0dd0f0d83136fb9ebc3dc6496d07abe94640a681fa5040109403b71b6ee34e29c37de6c96d07abe94034a6a225410020504cdc086e34fa98b46ff52848fd24a8f55856990b6117fcac9c8", + "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)" + } + ] + }, + { + "seqno": 106, + "wire": "88e4e10f0d8365b0b9efc7e06496d07abe94640a681fa504010940bb71b66e32e29c37de6c96df3dbf4a05c53716b504008140bb702fdc642a62d1bfc155856402034fffdfdedd", + "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)" + } + ] + }, + { + "seqno": 107, + "wire": "88e7e40f0d8369f10bf2cae36496d07abe94640a681fa5040109408ae32d5c13ca70df7b6c96df3dbf4a05c53716b504008140bb702fdc69d53168dfc4558465c7da6b7f0b9fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f0ba1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 108, + "wire": "88edea0f0d83642dbd408721eaa8a4498f5788ea52d6b0e83772ffd1ea6496d07abe94640a681fa5040109403b71a72e05b5386fbdd0ca55851322782dbb7f049fc7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b6112f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad844bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 109, + "wire": "88f3f00f0d8369b683c3d6ef6496d07abe94640a681fa5040109408ae340b81129c37def6c96df3dbf4a05c53716b504008140bb702fdc69f53168dfd0e1e0df55856402036cff", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "886196dc34fd280654d27eea0801128166e341b8d34a62d1bf5f88352398ac74acb37f0f0d83682d37c8db5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109403b71b0dc1054e1bef76c96d07abe940054d27eea080102806ee340b8dbea62d1bfd655851322784c877f0a9fc7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4f7f0aa1c7937a92d87a54ae73a4e419272b60797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 111, + "wire": "88c6c50f0d8365a0bfcfe2c46496d07abe94640a681fa5040109408ae01cb8cbaa70df7b6c96df697e94032a436cca0801028215c6ddb8d38a62d1bfdc558571b03ce3df7f049fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 112, + "wire": "88cccb0f0d836c0cb7d5e8ca6496d07abe94640a681fa50401094102e341b8c854e1bef76c96d07abe940054d27eea080102806ee341b801298b46ffe2558365f7df7f049fc7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2d2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 113, + "wire": "88d2ee5895aec3771a4bf4a54759093d85fa5291f9587316007f7b8b84842d695b05443c86aa6f7f1e842507417f798624f6d5d4b27f5f911d75d0620d263d4c795ba0fb8d04b0d5a75a839bd9ab", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "886196dc34fd280654d27eea0801128166e341b8d36a62d1bf4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028c81b52423f15450ff4085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8d38a62d1bf5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023435f2408b4d8327535532c848d36a3f8b96b2288324aa26c193a964c9c8c6", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "88c4de0f0d836d90b3e8c3dd6496df3dbf4a002a6e2d6a080212806ae36ddc038a70df7b6c96c361be94642a436cca080112817ae09eb8db8a62d1bff555857db7dc0b3f7f119fc7937a92d87a54ae73a4e419272be0717968313ad8bc72857f439ce75c87a77f11a2c7937a92d87a54ae73a4e419272be0717968313ad8bc72857f439ce75c87a6e3ccff7cae0ae152b9ce9390649caf81c5e5a0c4eb62f1ca15fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 116, + "wire": "88cae40f0d8369c75beec9e36496e4593e9403aa6e2d6a080212806ee36e5c6c4a70df7b6c96df3dbf4a01c53716b504008940bd71a15c6db53168df52848fd24a8f558565979f69bf7f059fc7937a92d87a54ae73a4e419272be0757968313ad8bc72857f439ce75c87a77f05a2c7937a92d87a54ae73a4e419272be0757968313ad8bc72857f439ce75c87a6e3ccff7cae0ae152b9ce9390649caf81d5e5a0c4eb62f1ca15fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 117, + "wire": "88d1eb0f0d83744f0bf5d0ea6496dd6d5f4a09e521b665040109403f7190dc0054e1bef76c96d07abe9413aa436cca0801128215c13d704053168dffc4558475971b6b7f049fc7937a92d87a54ae73a4e419272be2697968313ad8bc72857f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272be2697968313ad8bc72857f439ce75c87a6e3cdff7cae0ae152b9ce9390649caf89a5e5a0c4eb62f1ca15fd0e739d721e9b8f36a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 118, + "wire": "88d7f10f0d83684d0b7f1c88ea52d6b0e83772ffd7f1d16c96c361be94642a436cca080112817ae09eb8db2a62d1bfcad07f039fc7937a92d87a54ae73a4e419272be2717968313ad8bc72857f439ce75c87a77f03a2c7937a92d87a54ae73a4e419272be2717968313ad8bc72857f439ce75c87a6e3ccff7cae0ae152b9ce9390649caf89c5e5a0c4eb62f1ca15fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 119, + "wire": "88dc5f88352398ac74acb37f0f0d8369b703c3dc5892a47e561cc58190b6cb800001f55db1d0627f6496dd6d5f4a05d532db42820084a019b817ee05c5386fbd6c96d07abe940054d27eea080102806ee341b80714c5a37fd1558368006f7f069fc7937a92d87a54ae73a4e419272880caf2d06275b178e50afe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272880caf2d06275b178e50afe8739ceb90f4dc7997cae0ae152b9ce9390649ca2032bcb4189d6c5e3942bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 120, + "wire": "88e4c50f0d837196c1cae3c46497dd6d5f4a05d532db42820084a01ab8db77196d4e1bef7f6c96d07abe940054d27eea0801028172e05eb8d054c5a37fd755856990ba27bf7f049fc7937a92d87a54ae73a4e419272880d2f2d06275b178e50afe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272880d2f2d06275b178e50afe8739ceb90f4dc7997cae0ae152b9ce9390649ca2034bcb4189d6c5e3942bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 121, + "wire": "88eacb0f0d83659683d0e9ca6496dd6d5f4a05d532db42820084a05eb807ee32ea9c37de6c96d07abe940054d27eea080102806ee341b81694c5a37fdd5585132278416f7f049fc7937a92d87a54ae73a4e419272880daf2d06275b178e50afe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272880daf2d06275b178e50afe8739ceb90f4dc79b7cae0ae152b9ce9390649ca2036bcb4189d6c5e3942bfa1ce73ae43d371e6d4fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 122, + "wire": "88f0d10f0d8374006fd6efd06496d07abe940bca65b6850401094006e341b81129c37def6c96d07abe940054d27eea080102806ee341b8db8a62d1bfe35583680e357f049fc7937a92d87a54ae73a4e41927288025e5a0c4eb62f1ca15fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e41927288025e5a0c4eb62f1ca15fd0e739d721e9b8f377cad0ae152b9ce9390649ca20097968313ad8bc72857f439ce75c87a6e3cda9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 123, + "wire": "886196dc34fd280654d27eea0801128166e341b8d36a62d1bfd80f0d83680e3ddd4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd86496d07abe940bca65b685040109403371a6ee01a5386fbd6c96d07abe940054d27eea080102806ee341b800a98b46ffeb558569978026ffc57f05a1c7937a92d87a54ae73a4e41927288025e5a0c4eb62f1ca15fd0e739d721e9b8f337cad0ae152b9ce9390649ca20097968313ad8bc72857f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 124, + "wire": "88c4de0f0d8375f701e3c3dd6496d07abe940bca65b685040109403371a6ae3225386fbd6c96d07abe940054d27eea080102806ee341b820298b46fff055851322784077d0cfce", + "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)" + } + ] + }, + { + "seqno": 125, + "wire": "88c7c65894a8eb10649cbf4a54759093d85fa52bb0ddc692ff4085aec1cd48ff86a8eb10649cbf0f0d0234337f29842507417f5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "886196dc34fd280654d27eea0801128166e341b8d38a62d1bfe60f0d836997dbebcbe56496d07abe940bca65b685040109403371a6ee01b5386fbd6c96d07abe940054d27eea080102806ee340b8dbaa62d1bf52848fd24a8f55851322784d07d3cbca", + "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)" + } + ] + }, + { + "seqno": 127, + "wire": "886196dc34fd280654d27eea0801128166e341b8d3ca62d1bfd06c96df697e94038a681d8a0801128266e34f5c03aa62d1bfc17b8b84842d695b05443c86aa6f5a839bd9ab4089f2b20b6772c8b47ebf93f1e3c3205e5a0c4eb62f1ca15fd0e739d721e9408bf2b4b4189d6c59091a4c4f01315885aec3771a4bcc5f92497ca589d34d1f6a1271d882a60b532acf7f5501337cb5c7bf7eb602b854b0025fd12b32f4986bfa1ce73af5152a7f5cc739cfbec1cb2989b8b6772d8c05710171014ffd9342374aa7ff3fbf7688e7bf73015c405c40798624f6d5d4b27f7f1188ea52d6b0e83772ff0f0d8371c6816496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e34f298b46ffb52b1a67818fb5243d2335502f2d06275b1721e9f", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "886196dc34fd280654d27eea0801128166e341b8d3ea62d1bf5f88352398ac74acb37f0f0d8365d039c1df5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae340b82694e1bef76c96d07abe940baa681fa50400814106e36fdc6de53168dfd25585700f36277f7f289fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f21a1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 129, + "wire": "88c6c50f0d8369c083c8e6c46496d07abe94640a681fa504010940b971a76e36f29c37de6c96e4593e94034a436cca0801028266e083704ea98b46ffd855856df79d799f7f049fc7937a92d87a54ae73a4e419272b616d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b616d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 130, + "wire": "88cccb0f0d83136d87ceecca6496d07abe94640a681fa5040109408ae340b81129c37def6c96df697e94032a436cca0801028215c6deb8d36a62d1bfde558578010b2eff7f049fc7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b627d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 131, + "wire": "88d2d10f0d8313c217d4f2d06496d07abe94640a681fa50401094086e34cdc136a70df7b6c96df697e94032a436cca0801028215c6deb8d38a62d1bfe47f039fc7937a92d87a54ae73a4e419272b60697968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b60697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff55850b6165f07f", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88d8d70f0d8369a719da4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd76496d07abe94640a681fa50401094082e36e5c65d5386fbd6c96df697e94032a436cca0801028215c6ddb8cbea62d1bfeb5585136269f73f7f069fc7937a92d87a54ae73a4e419272b6202f2d06275b17191a5fd0e739d721e9f7f06a1c7937a92d87a54ae73a4e419272b6202f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad880bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 133, + "wire": "88dfde0f0d830b4d07e1c4dd6496d07abe94640a681fa5040109408ae340b826d4e1bef76c96df697e94032a436cca0801028215c6deb810a98b46fff1558569f70026ff7f049fc7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b600af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad802bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 134, + "wire": "88e5e40f0d8365d781e7cae36496dc34fd282129a88950401094002e32ddc69a5386fbdf6c96e4593e94642a681d8a0801028176e34edc0854c5a37f52848fd24a8f55857de78416bf7f059fc7937a92d87a54ae73a4e419272b2112f2d06275b17191a5fd0e739d721e9f7f05a1c7937a92d87a54ae73a4e419272b2112f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cac844bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 135, + "wire": "88eceb0f0d836c416feed1ea6496d07abe94134a6a2254100425002b816ee09f5386fbdf6c96e4593e94642a681d8a0801028176e34edc03ca62d1bfc455856990bac8bf7f049fc7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b22697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cac89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 136, + "wire": "886196dc34fd280654d27eea0801128166e341b8d3ea62d1bf5f88352398ac74acb37f0f0d83138107408721eaa8a4498f5788ea52d6b0e83772ffda5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae340b82694e1bef76c96d07abe94640a436cca0801028072e34fdc03ca62d1bfce558579d101e07fdad9d8", + "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)" + } + ] + }, + { + "seqno": 137, + "wire": "88c4c30f0d83684d07c2dec16496d07abe94640a681fa5040109403d7000b81129c37def6c96e4593e94642a681d8a0801028176e34edc0894c5a37fd15583132db97f0b9fc7937a92d87a54ae73a4e419272b61657968313ad8b8c8d2fe8739ceb90f4f7f0ba1c7937a92d87a54ae73a4e419272b61657968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad8595e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 138, + "wire": "88cac90f0d8369a703c8e4c76496d07abe94640a681fa50401094082e041700ea9c37def6c96d07abe94640a436cca0801028072e01db80754c5a37fd75585640179c7ff7f049fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 139, + "wire": "88d0cf0f0d83684f8bceeacd6496d07abe94640a681fa504010940b371b0dc6df5386fbd6c96d07abe94640a436cca0801028072e01db80654c5a37fdd5585136f36d03f7f049fc7937a92d87a54ae73a4e419272b620af2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b620af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad882bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 140, + "wire": "88d6d50f0d836596d9d4f0d36496d07abe94640a681fa5040109408ae32d5c13ca70df7b6c96d07abe94640a436cca0801028072e34fdc0854c5a37fe37f039fc7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b61797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdffec", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "88dbda0f0d8368007bd94003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd96496d07abe94640a681fa50401094102e342b80794e1bef76c96df697e94032a436cca0801028215c6ddb810298b46ffe955856996c4177f7f059fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f05a1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 142, + "wire": "88e2e10f0d83680f07e0c4df6496d07abe94640a681fa5040109408ae34cdc6c4a70df7b6c96df697e94032a436cca0801028215c6deb8cbea62d1bfefc3cecdcc", + "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)" + } + ] + }, + { + "seqno": 143, + "wire": "88e4e30f0d8365f7dce2c6e16496d07abe94640a681fa504010940b771905c0854e1bef76c96e4593e94642a681d8a0801028176e34e5c6df53168dff1558579d109e7bfc5c4c3", + "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)" + } + ] + }, + { + "seqno": 144, + "wire": "88e7e60f0d83105d7be5c9e4c86c96df697e94032a436cca0801028215c6deb8d34a62d1bf52848fd24a8f55856990b627ff7f099fc7937a92d87a54ae73a4e419272b62657968313ad8b8c8d2fe8739ceb90f4f7f09a1c7937a92d87a54ae73a4e419272b62657968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad8995e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 145, + "wire": "88edec0f0d83644f8bebcfea6496d07abe94640a681fa50401094082e32fdc682a70df7b6c96df697e94032a436cca0801028215c6ddb820a98b46ffc455856990bac8bf7f049fc7937a92d87a54ae73a4e419272b6cb2bcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cb2bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2caf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 146, + "wire": "886196dc34fd280654d27eea0801128166e341b8d3ea62d1bf5f88352398ac74acb37f0f0d8365a0b7408721eaa8a4498f5788ea52d6b0e83772ffd85892a47e561cc58190b6cb800001f55db1d0627fde6c96df697e94032a436cca0801028215c6ddb8cb4a62d1bfcd558479f71d6fd7d6d5", + "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)" + } + ] + }, + { + "seqno": 147, + "wire": "88c3c20f0d8365f719c1dbc06496d07abe94640a681fa504010940b7702fdc6dc5386fbd6c96df697e94032a436cca0801028215c6dfb807d4c5a37fd0c8c7c6c0", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88c5c40f0d83640cb9c3ddc2e26c96e4593e94034a436cca0801028266e083704ca98b46ffd15585134db6c87f7f0b9fc7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9f7f0ba1c7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad842bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 149, + "wire": "88cac90f0d830bcd33c8e2c7e76c96df697e94032a436cca0801028215c6deb8d014c5a37fd655856990b6177f7f039fc7937a92d87a54ae73a4e419272b6cbabcb4189d6c5c64697f439ce75c87a77f03a2c7937a92d87a54ae73a4e419272b6cbabcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2eaf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 150, + "wire": "88cfce0f0d8371f743cde7ccec6c96d07abe94640a436cca0801028072e01db81654c5a37fdb5585640179d77fc2c1c0", + "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)" + } + ] + }, + { + "seqno": 151, + "wire": "88d1d00f0d8365f71ecfe9ce6496d07abe94640a681fa5040109408ae340b82694e1bef76c96d07abe94640a436cca0801028072e34fdc0094c5a37fde55856990bac87f7f069fc7937a92d87a54ae73a4e419272b62757968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b62757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 152, + "wire": "88d7ef5895aec3771a4bf4a54759093d85fa5291f9587316007f7b8b84842d695b05443c86aa6f7f18842507417f798624f6d5d4b27f5f911d75d0620d263d4c795ba0fb8d04b0d5a75a839bd9ab", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "886196dc34fd280654d27eea0801128166e341b8d814c5a37f4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcf0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028c89c524204515450f4085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8d854c5a37f5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436ee408b4d8327535532c848d36a3f8b96b2288324aa26c193a964c9c8c6", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "88c4c35894a8eb10649cbf4a54759093d85fa52bb0ddc692ffc20f0d023433c95f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "48826402c77689e7bf73015c405c2cff408ff2b5869a74d2590c35a73a1350e92f93b075a4f601d680bd94af1ca15fd0e739d721e97f09d2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f52f70da3521bfa06a5fc1c46a6bdd08d4d7baf8d4d5c36a97786e52f6ad0a64d3bd4d5bef29af86d5376f87f9f0f1fa29d29aee30c0e45fd18b44948ea1cc5b1721e962b3792d1fe1a481971b03c1f84c02f58a1a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd2948fcac398b0037b012a6c96dc34fd280654d27eea0801128166e341b8d814c5a37f6496dc34fd280654d27eea0801128166e341b8d814c5a37fcbcf550130d2ed", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "886196dc34fd280654d27eea0801128166e341b8db2a62d1bfef0f0d8369d139eecfed6496d07abe94640a681fa504010940bb71b6ae002a70df7b6c96df697e94032a436cca0801028215c6deb8cb8a62d1bf52848fd24a8f55841042079f7f1e9fc7937a92d87a54ae73a4e419272b617d7968313ad8b8c8d2fe8739ceb90f4f7f1ea1c7937a92d87a54ae73a4e419272b617d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85f5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 157, + "wire": "88c5f60f0d8369a659f5d6f46496d07abe94034a65b6850401094002e01eb8dbaa70df7b6c96d07abe94640a436cca0801028072e34fdc0b2a62d1bfc455856990bacb9f7f049fc7937a92d87a54ae73a4e419272b6cbebcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cbebcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2faf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 158, + "wire": "88cb5f88352398ac74acb37f0f0d83138ebb7f2388ea52d6b0e83772ffde5892a47e561cc58190b6cb800001f55db1d0627fec6c96d07abe94640a436cca0801028072e34fdc038a62d1bfcc55856990bacb7f7f069fc7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 159, + "wire": "88d3c50f0d83640f07c4e4c3f16c96df697e94032a436cca0801028215c6ddb8db4a62d1bfd155850b8d3ce3bf7f039fc7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9f7f03a1c7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad842bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 160, + "wire": "88d8ca0f0d8365a6ddc9e9c86496d07abe94640a681fa5040109408ae32d5c13ca70df7b6c96df697e94032a436cca0801028215c6deb8cbea62d1bfd755856996c420ff7f049fc7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b62717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 161, + "wire": "88ded00f0d8369a659cfefce6496d07abe94640a681fa5040109408ae340b81129c37def6c96df697e94032a436cca0801028215c6deb8d094c5a37fdd5585684d3820ff7f049fc7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 162, + "wire": "88e4d60f0d8371a79cd57f2bff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd56496d07abe94640a681fa5040109408ae340b82694e1bef76c96e4593e94642a681d8a0801028176e34e5c6dc53168dfe4dd7f049fc7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb405e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 163, + "wire": "88eadc0f0d8369e7dfdbc3dac96c96e4593e94034a436cca0801028266e08371a0a98b46ffe87f029fc7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4f7f02a1c7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff55856df79d75ef", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88efe10f0d8365f783e0c8df6496dc34fd2816d4d444a820084a099b8266e01c5386fbdf6c96e4593e94642a681d8a0801028176e34e5c6dd53168dfee55856990b8f3bf7f059fc7937a92d87a54ae73a4e419272b210af2d06275b17191a5fd0e739d721e9f7f05a1c7937a92d87a54ae73a4e419272b210af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cac842bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 165, + "wire": "886196dc34fd280654d27eea0801128166e341b8db2a62d1bfe80f0d8375965ee7cfe66496dd6d5f4a044a65b6a5040109410ae01cb8d3ea70df7b6c96d07abe940baa681fa5040081410ae001719694c5a37f52848fd24a8f5585700f36cb3f7f069fc7937a92d87a54ae73a4e419272b416d7968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b416d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad05b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 166, + "wire": "88c5ef0f0d836dc681eed6ed6496d07abe94640a681fa5040109408ae34f5c65c5386fbd6c96e4593e94642a681d8a0801028176e34edc0054c5a37fc455857de78406ff7f049fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 167, + "wire": "88cb5f88352398ac74acb37f0f0d8369c03f408721eaa8a4498f5788ea52d6b0e83772ffde5892a47e561cc58190b6cb800001f55db1d0627fde6c96df697e94032a436cca0801028215c6ddb82694c5a37fcc558579d0bc17ff7f069fc7937a92d87a54ae73a4e419272b6c817968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b6c817968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb205e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 168, + "wire": "88d3c50f0d8365d75cc4e4c36496d07abe94640a681fa50401094082e32fdc682a70df7b6c96df697e94032a436cca0801028215c6ddb8c814c5a37fd255856990b6cb3f7f049fc7937a92d87a54ae73a4e419272b6c857968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b6c857968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb215e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 169, + "wire": "88d9cb0f0d8369b6c3caeac96496d07abe94640a681fa50401094086e32ddc1054e1bef76c96df697e940baa436cca080102817ae340b801298b46ffd85585682db6f3bf7f049fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 170, + "wire": "88dfd10f0d8369a6c5d0f0cf6496d07abe94640a681fa50401094102e341b8c854e1bef76c96df697e94032a436cca0801028215c6ddb8d34a62d1bfde558465c7db17d7d6d5", + "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)" + } + ] + }, + { + "seqno": 171, + "wire": "88e2d40f0d831004cfd34003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd36496d07abe94640a681fa50401094102e34ddc6db5386fbd6c96df697e94032a436cca0801028215c6ddb8d36a62d1bfe27f079fc7937a92d87a54ae73a4e419272b6cb2bcb4189d6c5c64697f439ce75c87a77f07a2c7937a92d87a54ae73a4e419272b6cb2bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2caf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff558571e134f3bf", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "886196dc34fd280654d27eea0801128166e341b8d854c5a37fc56c96df697e94038a681d8a0801128266e34f5c03aa62d1bfe87b8b84842d695b05443c86aa6f5a839bd9ab4089f2b20b6772c8b47ebf94f1e3c05a697968313ad8bd36c8bfa1ce73ae43d3408bf2b4b4189d6c59091a4c4f01315885aec3771a4b4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5501337cecc7bf7eb602b854b04fafe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb26846e954ffe7f7f4a63dfbf5b015c2a58012fe895997a4c35fd0e739d7a8a953fae639ce7df60e594c4dc5b3b96c602b880b880a7fec9a11ba553ff9fdff7688e7bf73015c405c40798624f6d5d4b27fe70f0d8371c6816496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e36153168dff6a5634cf031f6a487a466aa05e5a0c4eb62e43d3f", + "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" + } + ] + }, + { + "seqno": 173, + "wire": "886196dc34fd280654d27eea0801128166e341b8db2a62d1bfea0f0d8369c75be9d3e86496d07abe94640a681fa50401094082e34d5c0bea70df7b6c96df697e94032a436cca0801028215c6dfb81714c5a37f52848fd24a8f558479f71d7f7f159fc7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9f7f15a1c7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad804bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 174, + "wire": "88c5f10f0d83642cbff0daef6496d07abe94640a681fa50401094082e01fb8db8a70df7b6c96df697e94032a436cca0801028215c6dfb800298b46ffc4558479f71d07e9e8e7", + "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)" + } + ] + }, + { + "seqno": 175, + "wire": "88c8f40f0d83642e3bf3ddf26496d07abe94640a681fa5040109408ae340b81129c37def6c96df697e94032a436cca0801028215c6deb82714c5a37fc7ec7f069fc7937a92d87a54ae73a4e419272b616d7968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b616d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 176, + "wire": "88cd5f88352398ac74acb37f0f0d83684277408721eaa8a4498f5788ea52d6b0e83772ffe45892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae340b826d4e1bef76c96df697e94032a436cca0801028215c6ddb8d38a62d1bfcfce7f069fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 177, + "wire": "88d5c50f0d8313ae3dc4eac36496d07abe94640a681fa50401094086e34cdc0094e1bef76c96df697e94032a436cca0801028215c6ddb807d4c5a37fd47f039fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff5585101c69e7ff", + "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" + } + ] + }, + { + "seqno": 178, + "wire": "88dbcb0f0d8369975bcaf0c96496d07abe94640a681fa5040109408ae340b82694e1bef76c96d07abe940baa681fa50400814106e36fdc640a62d1bfda55857de784cb7f7f059fc7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 179, + "wire": "88e1d10f0d8365b039d04003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfd06496d07abe94640a681fa504010940bd71b15c69d5386fbd6c96df697e94032a436cca0801028215c6ddb8cb8a62d1bfe155856990b6cb5f7f059fc7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b60757968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81d5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 180, + "wire": "88e8d80f0d8365b10bd7c4d6ca6c96d07abe940baa681fa50400814106e36fdc134a62d1bfe655857de784cb3fdddcdb", + "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)" + } + ] + }, + { + "seqno": 181, + "wire": "88eac65895aec3771a4bf4a54759093d85fa5291f9587316007f7b8b84842d695b05443c86aa6f7f1c842507417fef5f911d75d0620d263d4c795ba0fb8d04b0d5a75a839bd9ab", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "886196dc34fd280654d27eea0801128166e341b8db4a62d1bfcc0f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f4002747389028c81d5242062a8a14085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8db6a62d1bf5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023435f1408b4d8327535532c848d36a3f8b96b2288324aa26c193a964c7c6c5", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "88c37689e7bf73015c405c2cff408ff2b5869a74d2590c35a73a1350e92f93b075a4f6004f857b295e3942bfa1ce73ae43d37f14d2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f52f70da3521bfa06a5fc1c46a6bdd08d4d7baf8d4d5c36a97786e52f6ad0a64d3bd4d5bef29af86d5376f87f9f58a1a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd2948fcac398b0037b012a6c96dc34fd280654d27eea0801128166e341b8db4a62d1bf6496dc34fd280654d27eea0801128166e341b8db4a62d1bfc8cb550130798624f6d5d4b27fed", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "88ccda5894a8eb10649cbf4a54759093d85fa52bb0ddc692ffcb0f0d023433d05f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 185, + "wire": "88cedcbfcc0f0d023433d1be", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "48826402cfc97f0993b075a4f601f1057b295e3942bfa1ce73ae43d3c8c7c6c5c4ced1c3c2f10f1fff0d9d29aee30c0e45fd18b44948ea1cc5b1721e960d4d7fe7ec01f21f8440eb8f3a16be37c0cfc4481d09804cbad32db420bbf176008be29805f16c13a535aacc2a8b0aa2c3e3c785e5a0c4eb62e43d2a8b0d739d2742a2c350d0321e9a4f521516148e642a2c350d263d43a065b0f50ed498881d5222b190a39293546426c1a4c7a95161ac7315954587e2c801", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "886196dc34fd280654d27eea0801128166e341b8db6a62d1bfdf6c96df697e94038a681d8a0801128266e34f5c03aa62d1bf52848fd24a8fd7d44089f2b20b6772c8b47ebf94f1e3c0595e5a0c4eb62f4db22fe8739ceb90f4ff408bf2b4b4189d6c59091a4c4f01315885aec3771a4bd45f92497ca589d34d1f6a1271d882a60b532acf7fca7cecc7bf7eb602b854b02f2fe895997a6d917f439ce75ea2a54feb98e739f7d83965313716cee5b180ae202e2029ffb26846e954ffe7f7f4a63dfbf5b015c2a58012fe895997a4c35fd0e739d7a8a953fae639ce7df60e594c4dc5b3b96c602b880b880a7fec9a11ba553ff9fdff7688e7bf73015c405c40cb7f1d88ea52d6b0e83772ff0f0d8371c6816496d07abe9413ca65b6850400b4a099b8c82e000a62d1bf0f28c6a0e41d06f63498f5405a96b50ab376d42acddb51f6a17cd66b0a88370d3f4a002b693f758400b4a059b8d06e36da98b46ffb52b1a67818fb5243d2335502f2d06275b1721e9f", + "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" + } + ] + }, + { + "seqno": 188, + "wire": "886196dc34fd280654d27eea0801128166e341b8db8a62d1bf5f88352398ac74acb37f0f0d836db137c1eb5892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa50401094082e32fdc682a70df7b6c96e4593e94034a436cca0801028266e08371a1298b46ffcb55856996c426bf7f2c9fc7937a92d87a54ae73a4e419272b60657968313ad8b8c8d2fe8739ceb90f4f7f2ca1c7937a92d87a54ae73a4e419272b60657968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad8195e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 189, + "wire": "88c6c50f0d8369c6c3c8f2c46496d07abe94640a681fa50401094082e083719029c37def6c96df697e94032a436cca0801028215c6dfb80794c5a37fd155850b8e09c6bf7f049fc7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 190, + "wire": "88cccb0f0d8369969ace7f23ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfcb6496d07abe94640a681fa5040109408ae34cdc6c4a70df7b6c96d07abe94640a436cca0801028072e01db80714c5a37fd85585640179e07f7f059fc7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b60717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 191, + "wire": "88d3d20f0d83699745d5c4d16496d07abe94640a681fa5040109408ae32d5c13ca70df7b6c96df697e94032a436cca0801028215c6deb8cb6a62d1bfde55856990b6cb9f7f049fc7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 192, + "wire": "88d9d80f0d8369a69cdbcad7c36c96df697e94032a436cca0801028215c6deb8d34a62d1bfe355856990b8f3ff7f039fc7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a77f03a2c7937a92d87a54ae73a4e419272b6cb4bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2d2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 193, + "wire": "88dedd0f0d8369a643e0cfdcc86c96e4593e94642a681d8a0801028176e34e5c69c53168dfe87f029fc7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9f7f02a1c7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad842bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb55856990b8f83f", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "88e3e20f0d840b2f059fe5d4e16496dc34fd280654dc5ad410042504cdc68371a0a9c37def6c96d07abe940baa681fa5040081410ae001702ca98b46ffee5585700f36cb3f7f059fc7937a92d87a54ae73a4e419272b40797968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b40797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad01e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 195, + "wire": "88e9e80f0d8310020febdae7d96c96df697e94032a436cca0801028215c6deb8d894c5a37f52848fd24a8f55856990b6cbbf7f049fc7937a92d87a54ae73a4e419272b6cb6bcb4189d6c5c64697f439ce75c87a77f04a2c7937a92d87a54ae73a4e419272b6cb6bcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2daf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 196, + "wire": "88efee0f0d8369b7dcf1e0ed6496d07abe94640a681fa5040109408ae340b82694e1bef76c96d07abe94640a436cca0801028072e01db82754c5a37fc4558464017c007f049fc7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b6d017968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb405e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 197, + "wire": "886196dc34fd280654d27eea0801128166e341b8db8a62d1bf5f88352398ac74acb37f0f0d83699799408721eaa8a4498f5788ea52d6b0e83772ffe95892a47e561cc58190b6cb800001f55db1d0627f6496d07abe94640a681fa5040109408ae340b826d4e1bef76c96df697e94032a436cca0801028215c6deb8d854c5a37fcec6c5c4558479f71e17", + "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" + } + ] + }, + { + "seqno": 198, + "wire": "88c4c30f0d8365b007c2edc16496d07abe94640a681fa5040109403d7002b810a9c37def6c96df697e94032a436cca0801028215c6dfb816d4c5a37fd1558479f71d67ecebea", + "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)" + } + ] + }, + { + "seqno": 199, + "wire": "88c7c60f0d8365e13fc5f0c46496d07abe94640a681fa5040109408ae340b810a9c37def6c96e4593e94034a436cca0801028266e083704ca98b46ffd4558579d0b8d39f7f0e9fc7937a92d87a54ae73a4e419272b62657968313ad8b8c8d2fe8739ceb90f4f7f0ea1c7937a92d87a54ae73a4e419272b62657968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad8995e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 200, + "wire": "88cdcc0f0d8365d783cb4003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfcb6496d07abe94640a681fa50401094102e34e5c03aa70df7b6c96d07abe94640a436cca0801028072e34fdc032a62d1bfdb55856996c4267f7f059fc7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9f7f05a1c7937a92d87a54ae73a4e419272b6012f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad804bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 201, + "wire": "88d4d30f0d83682f39d2c4d16496d07abe94640a681fa50401094102e341b8c854e1bef7d0e0558565c65f03ff7f039fc7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4f7f03a1c7937a92d87a54ae73a4e419272b62697968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89a5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 202, + "wire": "88d9d80f0d8365e0b5d7c9d66496d07abe94640a681fa5040109408ae34cdc6c4a70df7bd2e57f029fc7937a92d87a54ae73a4e419272b6cbabcb4189d6c5c64697f439ce75c87a77f02a2c7937a92d87a54ae73a4e419272b6cbabcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2eaf2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeffd7", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88dddc0f0d83134ebddbcddad96c96df697e94032a436cca0801028215c6deb810a98b46ffe955856990b6cb9f7f039fc7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9f7f03a1c7937a92d87a54ae73a4e419272b610af2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad842bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 204, + "wire": "88e2e10f0d8375979de0d2df6496d07abe94640a681fa5040109408ae32d5c13ca70df7b6c96e4593e94642a681d8a0801028176e34edc038a62d1bfef55856990bacbffd8d7d6", + "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)" + } + ] + }, + { + "seqno": 205, + "wire": "88e5e40f0d836de741e3d5e26496d07abe94640a681fa5040109408ae01ab81029c37def6c96d07abe94640a436cca0801028072e01db81754c5a37ff2558565975f65ef7f079fc7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4f7f07a1c7937a92d87a54ae73a4e419272b626d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 206, + "wire": "88ebea0f0d836c4017e9dbe86496d07abe94640a681fa5040109408ae340b81129c37def6c96df697e94032a436cca0801028215c6ddb8d894c5a37f52848fd24a8f55856990bacbdf7f059fc7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b606d7968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad81b5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 207, + "wire": "88f2f10f0d8313c207f0e2efcd6c96df697e94032a436cca0801028215c6deb8c854c5a37fc3d27f029fc7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a77f02a2c7937a92d87a54ae73a4e419272b6cbcbcb4189d6c5c64697f439ce75c87a6e3ccff7cae0ae152b9ce9390649cadb2f2f2d06275b17191a5fd0e739d721e9b8f32a7f48ed69a4604bbabeedf0ddcf81ffeff", + "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)" + } + ] + }, + { + "seqno": 208, + "wire": "886196dc34fd280654d27eea0801128166e341b8db8a62d1bf5f88352398ac74acb37f0f0d83640d35408721eaa8a4498f5788ea52d6b0e83772ffe95892a47e561cc58190b6cb800001f55db1d0627fde6c96d07abe94640a436cca0801028072e01db8c814c5a37fcb7f069fc7937a92d87a54ae73a4e419272b61717968313ad8b8c8d2fe8739ceb90f4f7f06a1c7937a92d87a54ae73a4e419272b61717968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad85c5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff5583132e33", + "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" + } + ] + }, + { + "seqno": 209, + "wire": "88c6c50f0d8369e65ac4efc3da6c96df697e94032a436cca0801028215c6dfb80714c5a37fd0558479f71e177f049fc7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9f7f04a1c7937a92d87a54ae73a4e419272b6212f2d06275b17191a5fd0e739d721e9b8f337cad0ae152b9ce9390649cad884bcb4189d6c5c64697f439ce75c87a6e3cca9fd23b5a691812eeafbb7c3773e07ffb", + "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)" + } + ] + }, + { + "seqno": 210, + "wire": "88cbca0f0d8365971bc94003703370ff2bacf4189eac2cb07f33a535dc61835529d7f439ce75c87a58f0c918ad9ad7f34d1fcfd297b5c1fcde875297f76b52f6adaa5ee1b5486fe852fe0e2a6f87229af742a6bdd7d4c9c61329938df3297b569329bf0673a9ab7eb329ab86d52fe0ce653743a0ca6adfb4ca70d3b4ca6be174ca64d37d4d78f9a9ab4e753869c8a6be1b54c3934a97b568534c3c54c9a77a97f06852f69dea6edf0a9af567531e0854d7b70299f55e5316ae3fcfc96496d07abe94640a681fa50401094082e36e5c03aa70df7b6c96df697e94032a436cca0801028215c6deb8d38a62d1bfd75584136268417f059fc7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4f7f05a1c7937a92d87a54ae73a4e419272b62797968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cad89e5e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 211, + "wire": "88d2d10f0d8365f75ed0c4cf6496d07abe94640a681fa50401094082e32fdc682a70df7b6c96d07abe94640a436cca0801028072e34fdc1014c5a37fdd558579d101d7bf7f049fc7937a92d87a54ae73a4e419272b6c897968313ad8b8c8d2fe8739ceb90f4f7f04a1c7937a92d87a54ae73a4e419272b6c897968313ad8b8c8d2fe8739ceb90f4dc7997cae0ae152b9ce9390649cadb225e5a0c4eb62e3234bfa1ce73ae43d371e654fe91dad348c097757ddbe1bb9f03ffdff", + "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)" + } + ] + }, + { + "seqno": 212, + "wire": "88d8ca5895aec3771a4bf4a54759093d85fa5291f9587316007f7b8b84842d695b05443c86aa6f7f19842507417f798624f6d5d4b27f5f911d75d0620d263d4c795ba0fb8d04b0d5a75a839bd9ab", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "886196dc34fd280654d27eea0801128166e341b8dbaa62d1bfd10f28c332505420c7a8d20400005b702cbef38ebf00f8761fba3d6818ffe4a82a0200002db8165f79c75f83ed4ac699e063ed490f48cd540b8ea1d1e9262217f439ce75c87a7f400274738a028cba2524232cc551434085aec1cd48ff86a8eb10649cbf6496dc34fd280654d27eea0801128166e341b8dbca62d1bf5899a8eb10649cbf4a5761bb8d25fa529b5095ac2f71d0690692ff0f0d023436ec408b4d8327535532c848d36a3f8b96b2288324aa26c193a964c8c7c5", + "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" + } + ] + }, + { + "seqno": 214, + "wire": "48826402c47689e7bf73015c405c2cff408ff2b5869a74d2590c35a73a1350e92f8db075a4f601c7195eca578e50ff7f1ad2acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f52f70da3521bfa06a5fc1c46a6bdd08d4d7baf8d4d5c36a97786e52f6ad0a64d3bd4d5bef29af86d5376f87f9f0f1fa29d29aee30c0e45fd18b44948ea1cc5b1721e962b3792d1fe1a4819744003ff09805f58a1a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd2948fcac398b0037b012a6c96dc34fd280654d27eea0801128166e341b8dbaa62d1bf6496dc34fd280654d27eea0801128166e341b8dbaa62d1bfc9cc550130cfeb", + "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" + } + ] + }, + { + "seqno": 215, + "wire": "88ccdf5894a8eb10649cbf4a54759093d85fa52bb0ddc692ffcb0f0d023433d15f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 216, + "wire": "88cee1bfcc0f0d023433d2be", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "88cee1bfcc0f0d023433d2be", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "886196dc34fd280654d27eea0801128166e341b8dbca62d1bfe2c0cd0f0d023433d3bf", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_28.json b/http/http-client/src/test/resources/hpack-test-case/story_28.json new file mode 100644 index 0000000000..0acee77b5a --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_28.json @@ -0,0 +1,5549 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264010f1f929d29aee30c78f1e17a0d5752c86a9721e9630f0d01306196dc34fd280654d27eea0801128166e059b8cbea62d1bf7686a0d34e94d727", + "headers": [ + { + ":status": "301" + }, + { + "location": "http://www.linkedin.com/" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:13:39 GMT" + }, + { + "server": "lighttpd" + } + ] + }, + { + "seqno": 1, + "wire": "88768c86b19272ad78fe8e92b015c30f288afc5b3e45b25fbd05e0ff4003703370f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff4087f2b5065adb4d2794c02f7de9db4f49f9e0c396bf2ee22ebc564d041f408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934f7b8b84842d695b05443c86aa6f4085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff5886a8eb2127b0bf5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70ddc9550130798624f6d5d4b27f408721eaa8a4498f5788ea52d6b0e83772ff5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "88cb54919d29aee30c78f1e17a0d5752c86a9721e96c96df697e94640a6a2254100225042b8d337190a98b46ff5f8b497ca58e83ee3412c3569fcac10f0d8368426b4084f2b124ab04414b414d588ca47e561cc58190884d3c217f6496e4593e94640a6a22541002ca8215c69db82654c5a37f6196dc34fd280654d27eea0801128166e059b8d054c5a37fc6", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88d2c45f86497ca582211fc6cf0f0d830badbbc2588ca47e561cc5804cbee89c759f6496df3dbf4a01e521b6650400b2a001702f5c0b4a62d1bfc1c9", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88d5c76c96d07abe9413ea6a225410022502edc0bb719694c5a37fc6c9d20f0d830840d7c5588ca47e561cc58190842f81d0ff6496df697e9413ea6a22541002ca8176e09ab8d894c5a37fc4cc", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88d8ca6c96df697e94640a6a2254100225042b8d337190298b46ffc4d5cc0f0d8369d137c8588ca47e561cc58190884d81f07f6496e4593e94640a6a22541002ca8215c6c371b0a98b46ffc7cf", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88dbcd6c96df697e94640a6a2254100225042b8d33704fa98b46ffc7d8cf0f0d840bcdb21fcb588ca47e561cc58190884d89e7bf6496e4593e94640a6a22541002ca8215c6dbb807d4c5a37fcad2", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88ded0c3ceda7f1d94e7affdbfa9ff6e78db93c4adc9b33de4430c3041d20f0d84782d38d7ce588ca47e561cc58190884d3c00ff6496e4593e94640a6a22541002ca8215c69db801298b46ffcdd5", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88e10f288fce12c0d3ed9631beefda958d33c0c7e07f01939b3a49e35038f8f397633811db1fa4430c3041dfdedd640130dc5f87352398ac4c697fdb6196dc34fd280654d27eea0801128166e059b8d32a62d1bf550131dbdad95886a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88e7d96c96df3dbf4a09b535112a080112817ee01eb806d4c5a37f5f89352398ac7958c43d5fe5c8dc0f0d03333631d8588ca47e561cc5819085e780d07f6496e4593e94640a6a22541002ca8115c65ab82694c5a37fc4df", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88ebdd6c96e4593e94642a6a225410022502fdc086e05a53168dff5f87352398ac5754dfe97f0a93bd7a4aaa96feff13e5f1469bdc5f31e1861820e1588ca47e561cc58190b4e32d34d76496dc34fd280129a4fdd41002ca8176e01ab82794c5a37f6196dc34fd280654d27eea0801128166e059b8d34a62d1bf0f0d8365a79fe5", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88f1e36c96d07abe940b2a436cca080112817ee019b8cbca62d1bfc3eee50f0d83081c17588ca47e561cc5804d34e899133f6496df697e940b2a436cca08016540bf700ddc69d53168dfc1e8", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "887684aa6355e7c2cfeae94088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37ff2ce7f37d2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 13, + "wire": "880f0d840b4f3cf7eb6c96d07abe941094d444a820044a05bb8d86e05f53168dff4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196dc34fd280654d27eea0801128072e059b827d4c5a37f6496dc34fd280654d27eea080112817ae059b827d4c5a37fecf8558413620b7f5890a47e561cc581a644007d295db1d0627f7686c58703025c1f", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "880f0d023335f26c96e4593e941054ca3a941000d2817ee361b8c814c5a37fc46196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46ffdcfe55850b8f082e7f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497fc34085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88c20f0d023335c9bec1c3dfbfc0c4", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "887f3a842507417f7b8b84842d695b05443c86aa6ffa6c96dc34fd280656d27eeb0801128166e059b8d36a62d1bf0f1388d0058058dd6e51395f911d75d0620d263d4c795ba0fb8d04b0d5a758a7aec3771a4bf4a54759360ea44a7b29fa529b5095ac2f71d0690692fd2948fcac398b038069e0036496dc34fd281029a4fdd410022502cdc0b371a6d4c5a37f0f0d83109f7b6196dc34fd280654d27eea0801128166e059b8d36a62d1bf76025153", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88c5e70f28caa4903607db0bcf3eb32d3320d60b92ba558657db17da85f359ac2a20d07abe94036b681fa58400b4a059b8166e34da98b46ffb52b1a67818fb5243d2335502fdad1d49416cee55c87a7f7f14b7bdae0fe74eac8a5fddad4bdab6a9a725f52f70da3521bfa06a5fc1c46a6bdd09d4d7baf9d4d5c36a9ba1d0353269bea5ed5a14d30f1fe758a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfc86496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335c2c1", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88c5c75a839bd9ab6496dc34fd281754d27eea0801128166e059b8d36a62d1bfc40f0d83085a077f0b88ea52d6b0e83772ff589caec3771a4bf4a54759360ea44a7b29fa5291f958731600880fb8007f", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "89c9cbc16496d07abe940054ca3a940bef814002e001700053168dffc70f0d0130c058b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfcf", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88768c86b19272ad78fe8e92b015c30f28aea0754d07f3de017c503aa680b52d6a3f9fb53896c418f5401fb52f9e919aa828355d4b21aa5c87a7ed4d634cf0317f08f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff7f2994e935b77cdff37b5bd0b284d9b7839ec1bbc4107f408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fd1d3f55886a8eb2127b0bf5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd6196dc34fd280654d27eea0801128166e059b8d3ea62d1bf550130798624f6d5d4b27fcbcdf74087f2b4a85adb4d279778a08de091a648d099948065d8c520e40b6c8c92b4d47f", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "887686a0d34e94d7270f28aea0754d07f3de017c503aa680b52d6a3f9fb53896c418f5401fb52f9e919aa828355d4b21aa5c87a7ed4d634cf031c8c7c6d9db640130c6f8c4c3c2c1ced0fac052848fd24a8f0f138afe42e3a2136f09d77f9f6c96e4593e941094cb6d4a08010a8205c13d700053168dff0f0d83085b07", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88cc54919d29aee30c78f1e17a0d5752c86a9721e96c96df3dbf4a05c521b6650400894006e09ab8d094c5a37ff8ded40f0d83081a6b588ca47e561cc5804d3a20882fff6496c361be940b8a436cca08016540b9702d5c03ea62d1bf6196dc34fd280654d27eea0801128166e059b8d814c5a37fd5", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88d1c26c96e4593e940baa6a225410022504cdc03f71b1298b46ff5f86497ca582211fe3d90f0d837c2e3d588ca47e561cc5819005c79965bf6496c361be940bca6a22541002ca8176e05fb826d4c5a37fc2d9", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88f76196dc34fd280654d27eea0801128166e059b8d854c5a37f5f87352398ac4c697fcedbf8f7e95886a8eb10649cbff7", + "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\"" + } + ] + }, + { + "seqno": 25, + "wire": "88e9bfe0eadf0f0d023335c0e2", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "880f0d023335deeff5eeedbfe855840b8f0842ecf1eb", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "89e7e9dfdbc10f0d0130dddaeb", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88d9ca6c96c361be940094d27eea080112817ae041719714c5a37f5f87352398ac5754dfeb7f1a942c3ef479d3c3478f397c624fae2f98f0c30c107fe2588ca47e561cc58190b626df7d9f6496dd6d5f4a0195349fba8200595020b8276e01a53168dfc60f0d821099e2", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88decf6c96dc34fd2800a9b8b5a820044a00171b7ae01f53168dffc2ef7f0293bd7a4aaa96feff13e5f1469bdc5f31e1861820e6588ca47e561cc5804e01a79e745f6496dd6d5f4a002a6e2d6a0801654006e00371a654c5a37fca0f0d840842e03fe6", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88e20f28aea0754d07f3de017c503aa680b52d6a3f9fb53896c418f5401fb52f9e919aa828355d4b21aa5c87a7ed4d634cf031e17f019487f76c7936bfc5c7a5bbb28e7fbef61f707c4107e0f3f5d7dfdedd6196dc34fd280654d27eea0801128166e059b8db4a62d1bfdcdbe8eaca7f1b96005f69b8c410cadb658c8e902d09b702f92400c2291dd80f138afe42e3a2136f09d77f9fd70f0d8369d0b5", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "88f6ccedf7ec0f0d023335bfef", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "887684aa6355e7c0cdddea4088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37fface7f28d2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 33, + "wire": "880f0d023335ef6c96e4593e941054ca3a941000d2817ee361b8c814c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46ffd47b8b84842d695b05443c86aa6f55850b8f084e7f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497f7686c58703025c1f4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "895f911d75d0620d263d4c795ba0fb8d04b0d5a7c3f9f5cd0f0d0130f7f4bf", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88f30f28aea0754d07f3de017c503aa680b52d6a3f9fb53896c418f5401fb52f9e919aa828355d4b21aa5c87a7ed4d634cf031f27f0f94f19c3af226bc7b899eeeda01af8f5367cfb2083ff1c4c0e8f0efee6196dc34fd280654d27eea0801128166e059b8dbea62d1bfedecf9fbdb7f0f97202391a9442906d3ad3e41102d38dc8095b71a79e8c527e90f138afe42e3a2136f09d77f9fe80f0d8369d0b5", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88cebfddedfacdccc2dccb", + "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\"" + } + ] + }, + { + "seqno": 37, + "wire": "887f3b842507417fde58a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfc46496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335c276025153", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "880f0d0233355a839bd9abcfcecdcce2cb55850b8f09907fcac9c8", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88e3ccbf6496d07abe940054ca3a940bef814002e001700053168dffc60f0d0234337f0588ea52d6b0e83772ff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfcb", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "88768c86b19272ad78fe8e92b015c30f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031f7f16f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff7f0c95effb8effadbd2d36cbdd67fdbbefd79c5dac9a083f408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fd3cff75886a8eb2127b0bf5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd6196dc34fd280654d27eea0801128166e05ab800a98b46ff550133798624f6d5d4b27fc9ccef7f12968e47c24648f85e295e7c001b4f36f81d6491842318cb52848fd24a8f0f138afe42e3a2136f09d77f9f6c96c361be9413aa693f7504003ea01cb8276e082a62d1bf0f0d83702eb9", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88ca54919d29aee30c78f1e17a0d5752c86a9721e96c96df697e940094d444a820044a01db8db3704ca98b46ff5f8b497ca58e83ee3412c3569fdfd20f0d836801174084f2b124ab04414b414d588ca47e561cc5804f3ad882f3ff6496e4593e940094d444a820059500edc6ddb810a98b46ff6196dc34fd280654d27eea0801128166e05ab801298b46ffd3", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "88d1c46c96d07abe9413ea6a225410022502edc0bb719694c5a37ff7d7e40f0d03363238c2588ba47e561cc581965e0be0776496e4593e940894be522820044a05cb8cbf700fa98b46ffc1d6", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "88d4c7f9d9e60f0d83081a6bc4588ca47e561cc58190b4f81c685f6496dd6d5f4a0195349fba8200595000b8cbd700d298b46fc3d86c96c361be940094d27eea080112817ae32e5c644a62d1bf7f1693cda266caee34789f26cf135fdf93d221861820", + "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==" + } + ] + }, + { + "seqno": 44, + "wire": "88d8cb6c96e4593e94642a6a2254100225000b8205c03ca62d1bff5f86497ca582211fecdf0f0d840baf89efca588ca47e561cc5819089903adb5f6496df3dbf4a321535112a0801654002e09cb8cb8a62d1bfc9de", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "88dccf6c96df697e94132a6a2254100225020b8105c680a62d1bffc1ef7f0494e7affdbfa9ff6e78db93c4adc9b33de4430c3041e30f0d84085e719fce588ca47e561cc5819036eb4fb4e76496e4593e94132a6a22541002ca8105c0b9704f298b46ffcde2", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "88e0d36c96d07abe941094d444a820044a05db8105c684a62d1bffd2f3e60f0d8475d0043fd1588ca47e561cc5819036165c79ff6496df697e941094d444a820059502edc0b77190a98b46ffd0e5", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "887689bf7b3e65a193777b3ff10f0d03333532e96196dc34fd280654d27eea0801128166e05ab806d4c5a37f", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "88e50f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031fe4e3e2f7f3640130e25f87352398ac4c697fe16196dc34fd280654d27eea0801128166e05ab80694c5a37f550131e0ebee5886a8eb10649cbfe0df0f138afe42e3a2136f09d77f9fde0f0d83702eb9", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "886c96c361be940094d27eea080112807ee005719754c5a37f6496c361be9403ea693f75040089403f7002b8cbaa62d1bf5f911d75d0620d263d4c1c88ad6b0a8acf520b409221ea496a4ac9b0752252d8b16a21e435537f858cd50ecf5f0f0d83085e7358a7a47e561cc581b032c845f4a576c74189f4a54759360ea44a7b29fa529b5095ac2f71d0690692ffc84087aaa21ca4498f57842507417f7f3388cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "887684aa6355e76196dc34fd280654d27eea0801128166e05ab80714c5a37fcaeaf54088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37f4085aec1cd48ff86a8eb10649cbfca7f36d2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 51, + "wire": "887f05842507417fcf58a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfc16496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335c576025153", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "880f0d0233355a839bd9ab6c96e4593e941054ca3a941000d2817ee361b8c814c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46ffd77b8b84842d695b05443c86aa6f55850b8f09977f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497f7686c58703025c1fcc", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "88c30f0d023335c4ccc2c5dbbfc0be", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "89dbc1c66496d07abe940054ca3a940bef814002e001700053168dffd00f0d01307f0c88ea52d6b0e83772ff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfcf", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "88768c86b19272ad78fe8e92b015c30f288afc5b3e45b25fbd05e0ff7f10f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fc76c96e4593e94109486d99410022500fdc6dbb8d094c5a37f5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd6196dc34fd280654d27eea0801128166e05ab80794c5a37f4087f2b4a85adb4d2797680e0a591a948f3f1b8cb4e14a28dc0bed806fbcd006df7f3093d98b3bfbde347cc11db9858b8deae786bd9041e5798624f6d5d4b27fc9d3", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88c70f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031fc67f0094b2fd17b168d3d2bb2c467e1ab4578e7cb93c4107c6cfda6496df3dbf4a002a651d4a05f740a0017000b800298b46ff5886a8eb2127b0bfc6c56196dc34fd280654d27eea0801128166e05ab807d4c5a37f550130c3ced8ea7f06968e47c24648f85e295e7c001b4f36f81d6491842318cb52848fd24a8f0f138afe42e3a2136f09d77f9f6c96c361be9413aa693f7504003ea01cb8276e082a62d1bf0f0d0130", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88f35f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03333532dcc3", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88d00f288afc5b3e45b25fbd05e0ffcfced7cdf1cbc3c97f0794bd7f5eff4c68e3e3ce6d98735afd3e910c30c107c3c8d3ddeff3e3", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88d154919d29aee30c78f1e17a0d5752c86a9721e96c96df697e940094d444a820044a05db807ee34d298b46fff4da7f0194e7affdbfa9ff6e78db93c4adc9b33de4430c3041e00f0d0236344084f2b124ab04414b414d588ca47e561cc5804f3c165e69df6496df3dbf4a019535112a0801654006e01ab8db8a62d1bfcad9", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "88d7c36c96e4593e94642a6a225410022502fdc086e05a53168dff5f87352398ac5754dfe07f0493342ea247eadfe27c9b0b2a18cf7910c30c107fe6588ca47e561cc58190b4e32c85ff6496dc34fd280129a4fdd41002ca8176e00571a794c5a37fcf0f0d03363033de", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88c10f0d83085b736c96c361be940bca435d8a08007940bd700cdc6da53168df0f13890880f36d05e65a0001768bca54a7d7f4e2e15c4e7f7fc7588ba47e561cc581b0bee34ebb6496e4593e940094ca3a941002ca8172e342b80754c5a37f6196dc34fd280654d27eea0801128166e05ab810298b46ffe3", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "88c60f0d8365a75c6c96df3dbf4a002a6e2d6a08010a8166e34e5c03ca62d1bf0f138a0b2169e79a75c780007fc2cb588ca47e561cc5804f89a65c71ef6496df697e9403ca6a22541002ca8005c13d719794c5a37fc1e6", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88c90f0d830b4e376c96e4593e940b6a5f291410020502fdc6dcb807d4c5a37f0f1389089f134d09f71f0001c5ce588ba47e561cc581b744c804d76496df697e9403ca651d4a08016540bd71b76e36d298b46fc4e9", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88cc0f0d830ba06f6c96e4593e940b2a681fa504003ea01cb8d3b700e298b46f0f1389089a105f7442700007c8d1588ca47e561cc5804f3a175d13bf6496df697e940054d444a8200595042b8215c6dd53168dffc7ec", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88cf0f0d830bad3d6c96d07abe940b2a612c6a080112806ae05cb8db4a62d1bf0f13890b227c2071c0b40003cbd4588ca47e561cc5804fb81640c8bf6496dc34fd281129a88950400b2a01db806ae34253168dffcaef", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88d20f0d831042df6c96d07abe94038a65b6a50400854086e09eb82794c5a37f0f13890b207596df740f0000ced7588ca47e561cc5804f89b6c0d3df6496df697e9403ca6a22541002ca8066e32f5c0bca62d1bfcdf2", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "88d50f0d83101c6f6c96c361be940b6a436cca08007940397196ee32d298b46f0f13890882f3af082cb40003d1588ca47e561cc5804cbef3ed3ad76497df3dbf4a01e521b6650400b2a01ab8dbd71a694c5a37ffd0f5dc", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "88d80f0d830baebb6c96dd6d5f4a01c521aec504003ca05cb8d3571a0298b46f0f13890880eb60009e00000fd4dd588ca47e561cc5804d002db4dbdf6496df3dbf4a01e521b6650400b2a0457021b8d3ca62d1bfd3f8", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "88db0f0d83136cb96c96dd6d5f4a05d521aec50400854086e09cb800298b46ff0f13890b20640cbedb800001d7e0588ca47e561cc581903efb8dba0f6496d07abe9413ca6a22541002ca8076e099b8d014c5a37fd6408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "88df0f0d830b4d376c96dd6d5f4a05a52f948a08007940bf71a76e09e53168df0f13890884f89e680d3c0003dbe4588ca47e561cc58190804cbc273f6496d07abe9413ca6a22541002ca816ae36edc6dc53168dfdac1", + "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" + } + ] + }, + { + "seqno": 71, + "wire": "88e20f0d84085d79bf6c96df697e941054c258d410022500d5c69ab82754c5a37f0f138a0b227dd7df69c740007fdee7588ca47e561cc5804f89c75a75bf6496df697e9403ca6a22541002ca8076e01bb826d4c5a37fddc4", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "887684aa6355e76196dc34fd280654d27eea0801128166e05ab810a98b46ff5f87352398ac4c697ffac74088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37f4085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf4003703370d2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 73, + "wire": "887f0d842507417fc458a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfc26496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335c776025153", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "880f0d0233355a839bd9ab6c96e4593e941054ca3a941000d2817ee361b8c814c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46ffcc7b8b84842d695b05443c86aa6f55850b8f09a17f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497f7686c58703025c1fcd", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "88c30f0d023335c4cdc2c5d0bfc0be", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "89d0c1c66496d07abe940054ca3a940bef814002e001700053168dffd20f0d0130da58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfcf", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "885f88352398ac74acb37f0f0d830802cf6c96dc34fd280654d27eea080112806ee34d5c65c53168df0f138a0b2d85f105a75c69e6ff768c86b19272ad78fe8e92b015c34084f2b124ab04414b414d588ca47e561cc58190b6079f65bf6497dd6d5f4a0195349fba820059500ddc699b80714c5a37ffd9e14087f2b5065adb4d2793b6ecd8cd4f77fc4f93c1edd76e6f4886186083cfca", + "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" + } + ] + }, + { + "seqno": 78, + "wire": "88c20f288afc5b3e45b25fbd05e0ff7f15f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fcc6c96df3dbf4a01f521b665040089400ae340b82794c5a37f5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd6196dc34fd280654d27eea0801128166e05ab811298b46ff4087f2b4a85adb4d27978dd6647e424b2b447a4680071d69c78b2b8f3e503637d97f06934fb149ed8df9030ddab69dd118b747d7c4107f550131798624f6d5d4b27fecd9df640130e10f0d8371b03b", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88cd0f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031fc87f0293ff6f6af55b26092872b134cf2e2ce7d0e4d041c8d6e26496df3dbf4a002a651d4a05f740a0017000b800298b46ff5886a8eb2127b0bfc8c76196dc34fd280654d27eea0801128166e05ab81654c5a37f550130c4f2dfe57f08968e47c24648f85e295e7c001b4f36f81d6491842318cb52848fd24a8f0f138afe42e3a2136f09d77f9f6c96c361be9413aa693f7504003ea01cb8276e082a62d1bf0f0d0130", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "887689bf7b3e65a193777b3f5f911d75d0620d263d4c795ba0fb8d04b0d5a70f0d03353337e4c4", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88bf5f87497ca589d34d1f0f0d83134e3fe5c5", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88e05f8b497ca58e83ee3412c3569f6c96df697e9403ca681fa50400894102e01fb80754c5a37f6196c361be940094d27eea080112816ae320b807d4c5a37f6496dc34fd280654d27eea080112816ae320b807d4c5a37fe7e9768344b2970f0d826441408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f5584782f34df5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "88e8e26c96df697e941054c258d4100225001b8066e34fa98b46ff6196c361be940094d27eea0801128205c033704fa98b46ff6496dc34fd280654d27eea0801128205c033704fa98b46ffeef0c40f0d8413416dcfc35584702f34dfc2", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88e454919d29aee30c78f1e17a0d5752c86a9721e96c96c361be940094d27eea080112817ae0417196d4c5a37f5f87352398ac5754dfeff4588ca47e561cc58190b626dd783f6496dd6d5f4a0195349fba8200595020b8266e36d298b46fd60f0d0239347f3b88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88768586b19272ff0f13a2fe5b95d211f03c020e4009965969a6d971d906571a6da724b8165b0800e34e39fcff6c96df697e94132a6a225410022502ddc65ab82714c5a37fd6d3f4f95889a47e561cc58197000f6196dc34fd280654d27eea0801128166e05ab81694c5a37f0f0d830804f7c2", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88d5fb6c96d07abe940bca65b6a504008940b37022b8dbaa62d1bfd90f138efe4b1b8c902d36d3521240dc07f3f7768dd06258741e54ad9326e61d5c1f4089f2b567f05b0b22d1fa868776b5f4e0df0f0d8313edb7c1c5", + "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" + } + ] + }, + { + "seqno": 87, + "wire": "88c1c46c96dc34fd280654d27eea0801128172e09bb8d3ea62d1bf6496e4593e9403aa693f7504008940b9704ddc69f53168df0f139f69c7dd75a035840d3acb8fb976edfbcd85eba179a6ef380c0f01f859134fff58a5a47e561cc58196dc69f6beabb63a0c4faa8eb26c1d4894f653f54da84ad617b8e83483497f408df2b1c88ad6b0b59ea90b62c693884bc5908339115b9f0f0d033437317f0a842507417f5f911d75d0620d263d4c1c88ad6b0a8acf520b", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "88ca0f13a1fe5c6dd79c209f08da700c8c6d85b00c2f3cd34d89e65e92e044e8596c226dafe76c96df3dbf4a05b521aec504008140bb700edc13ea62d1bfe25f87352398ac4c697f7b8b84842d695b05443c86aa6f5a839bd9ab588da47e561cc5804169a69a780007cc0f0d023433d0", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "88cf0f13a2fe5a249234ec6ec7205b95d6de65e6996e50880e8c81682d5c0b2d840071f7d9fe7f6c96df697e94132a6a225410022502ddc699b81654c5a37fe7e4c1c0588ca47e561cc58190b6cb800001ce0f0d840884c8bfd2", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "48826402768c86b19272ad78fe8e92b015c37f3c9fbdae0fe6f6ad0a69878a9934ef5376f854d392fa9ab86d53269bea69d593f94085aec1cd48ff86a8eb10649cbf5886a8eb10649cbf0f28bf213afb803493c7a66cfb52f9e919aa8292c861b92166b0a542e43d3f6a60f359ac2a20df3dbf4a004b681fa58400b2a059b816ae05b53168dff6a6b1a678180f1fc49d29aee30c0c8931ea5e92c861b92166b0a542e43d2c1ec8d05b3bb1523a23fca89de0659f8a91009f7fe2b2778197fe2a2401f8acde7249005903ce7c109d7dc09b2d2f0f0d0130d3cb", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "88c1bef4bfc8c76196dc34fd280654d27eea0801128166e05ab816d4c5a37ff0f6d8c7", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "88c20f288afc5b3e45b25fbd05e0ff7f02f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fca6c96df697e940baa65b68504008941337020b8d36a62d1bf5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70ddc37f359708196a3046e11d7640caf85e0be3148f89f75c6a36de177f3b93c17f7784a247f1b78aed2616ea05b8334d041ff7fddfcec6fcc70f0d8371b03b", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "88c90f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031fc47e9336bdd77d73dfc44d05d16fd186126b26e9a083c4d0c8fbfac2c1c6f8fee0cfc7f7f60f138afe42e3a2136f09d77f9ff50f0d0130", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "88f4f30f0d03353339cf6196dc34fd280654d27eea0801128166e05ab81714c5a37f", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "cccbcac9c80f28bf213afb803493c7a651f6a5f3d23355052590c37242cd614a85c87a7ed4c1e6b3585441be7b7e940096d03f4b08016540b3702d5c0b8a62d1bfed4d634cf0310f1fc49d29aee30c0c8931ea5e92c861b92166b0a542e43d2c1ec8d05b3bb1523a23fca89de0659f8a91009f7fe2b2778197fe2a2401f8acde7249005903ce7c109d7dc09b2d2f0f0d0130bed5", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "88cbcac9c80f28b6cbbb06edd93569c97e0bd81966fe1c0edf7da75d7ef059ba06af357dfbad337dd75f17da9ac699e060f64682d9dfed4c694d7aaaa3d75f95497ca589d34d1f649c7620a98326ed4b3cf36fac1fc30f0d0135c8d6", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "88f6f40f0d03383431d1bf", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88cc0f28ff0db607bfe02ec3373caff03e2bd2f1cd0c30c30c30c3b30430ecc93c83f10c3b667e5da4661861861877bfafbcd0c30c30c36bffb2cd0c30c30ea8b8a785ebba2ec30db773ec87ed4e25b1063d5007ed4be7a466aa05c7375a9721e9fb5340fcad0cc581c640e880007da983cd66b0a88341eafa500cada4fdd61002d28166e05ab81714c5a37fda9ac699e0637f08b6bdae0fe74eac8a5fddad4bdab6a97b86d1a90dfd0352fe0e23537c3906a6ae1b54bbc3729934df53869c8a5ed5a14d30f153269dffcf6495dc34fd2800a994752820000a0017000b800298b46fcc5892a8eb10649cbf4a536a12b585ee3a0d20d25f5f95352398ac4c697ec938ec4153064dda9679e6df583fc70f0d023433ccda", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "88d00f288afc5b3e45b25fbd05e0ffcbcad6c9d7c7c3c6c5550130798624f6d5d4b27fe8d7cf640130d10f0d8371b03b", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88ec0f0d831019736c96df3dbf4a09f5349fba82001d502fdc03f702053168df0f1389085f71971965b00000768bca54a7d7f4e2e15c4e7f7f4084f2b124ab04414b414d588ca47e561cc58190800dbafbbf6496d07abe9413ca6a22541002ca807ee36edc65953168dfcbee7f0d93b6ecd8cd4f77fc4f93c1edd76e6f4886186083dedf", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88d9f46c96dc34fd2816d4dc5ad410022500e5c10ae32da98b46fff3e0df588ca47e561cc5804eb2d36eb2f76496d07abe940b8a6e2d6a0801654006e05cb8cb4a62d1bfcf0f0d03313436f2", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "88e25f88352398ac74acb37f6c96df697e94032a65b6850400894106e05bb8c854c5a37f6196dc34fd280654d27eea0801128066e320b80754c5a37f6496dd6d5f4a01a5349fba820044a019b8c82e01d53168df4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbe6768344b2970f0d840beebcef408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f558465b034ff5890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "8b5f911d75d0620d263d4c795ba0fb8d04b0d5a7ebf752848fd24a8f0f138efe4b1b8c902d36d3521240dc07f3edf7f60f0d8313edb7dafd", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "88fc0f13a3fe5e699644575b6dc71a75b69991b95e75c69d959746f0dc92e05969c03cebee39fcff6c96d07abe9413aa436cca0801128176e05fb82714c5a37fbfc0eeed5888a47e561cc581c003dc0f0d033734317f3488ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "887684aa6355e7def2d7bf4088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37febea7f1fd2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 106, + "wire": "88f8f558a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfed6496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335e376025153", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "880f0d023335f66c96e4593e941054ca3a941000d2817ee361b8c814c5a37fcf6196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46fffbfa55850b8f09a77f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497f7686c58703025c1ff5", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "88c20f0d023335d4f5c1c35f87352398ac4c697fc0c1bf", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "88768586b19272ff0f13a2fe650b2eb4e32eb528c2d86313438e47a395f7c6cbee3cebd702cb4e89f699699fe76c96d07abe940814dc5ad410022502e5c13771a654c5a37fd15f87352398ac5754df7b8b84842d695b05443c86aa6f5a839bd9ab588da47e561cc5804169a69a780007f10f0d830804f7d2", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "88c30f13a1fe5a91b28e464928c619647dc138c85f742e8084196403b702cb4e89f699785fcf6c96d07abe940814dc5ad410022502e5c139704253168dffd60f0d830b6077c2bff2d3", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "89d3", + "headers": [ + { + ":status": "204" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "seqno": 112, + "wire": "89c5c1c06496d07abe940054ca3a940bef814002e001700053168dfff30f0d0130d458b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88768c86b19272ad78fe8e92b015c30f288afc5b3e45b25fbd05e0ff7f14f5bdae0fe6f43a94bfbb5a97b56d52f70daa437f4194bf838994df0e4329af7426535eebe65327184ca64e37cca5ed5a4ca6ae1b54bf833994dd0e8329c34ed329af85d329ab7ed329934df535e3e6a6ad39d4e1a7229af86d530e4d2a5ed5a14d30f153269dea5fc1a14bda77a9af567535edc1fcff408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fc76c96dd6d5f4a01b521b66504008940b77196ee34ca98b46f5f91497ca589d34d1f649c7620a98386fc2b3d5b842d4b70dd6196dc34fd280654d27eea0801128166e05ab81794c5a37f4087f2b4a85adb4d27972b521231c92cad3adb4069e6c658e36e403af8dc704d8b7f30936f4fa719636876609c6e3bf9b0a3fd3709a083f8f7dfcc5886a8eb10649cbff7c80f0d8371b03b", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "88c70f28bf45107f321682a4aa525fe7ed4e25b1063d5007ed4d03f2b43316007da983cd66b0a8837cf6fd2800ad94752c17dd028005c002e040a62d1bfed4d634cf031fc67f0094ede0dfee771cf17b9f2f7bb493317cf16bd78820c6cfc96496df3dbf4a002a651d4a05f740a0017000b800298b46ff5886a8eb2127b0bfc6c5c4550131fce4d1c27f05968e47c24648f85e295e7c001b4f36f81d6491842318cbe80f138afe42e3a2136f09d77f9f6c96c361be9413aa693f7504003ea01cb8276e082a62d1bf0f0d0130", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "887689bf7b3e65a193777b3feb0f0d03353338d46196dc34fd280654d27eea0801128166e05ab817d4c5a37f", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "88cf7f0f9fbdae0fe6f6ad0a69878a9934ef5376f854d392fa9ab86d53269bea69d593f9d1c70f28b6cbbb06edd93569c97e086171fbf85e7997aeb2cb8cb975e730b30df6df0bb7c4f5fbff6a6b1a678183d91a0b677fb531a535eaaa8f5f5f95497ca589d34d1f649c7620a98326ed4b3cf36fac1fcc0f0d0135c07f2b842507417f", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "88c25f87497ca589d34d1f0f0d03383539d9c2", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88d30f288afc5b3e45b25fbd05e0ffd2d1dad0decec2cc7f0a941e2ef818efc38f8f39bc68a326dcb7910c30c107550130798624f6d5d4b27fefdccd640130d80f0d8371b03b", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "88d70f28ff0db607bfe02ec3373caff03e2bd2f1cde21861861bb0ecc10c3b364f20fc430ed99f976919861861861defebef3430c30c30dadf2b6186186187545c53c2f5dd176186dbb9f643f6a712d8831ea803f6a5f3d2335502e39bad4b90f4fda9a07e568662c0e3207440003ed4c1e6b3585441a0f57d280656d27eeb08016940b3702d5c0bea62d1bfed4d634cf0317f06b6bdae0fe74eac8a5fddad4bdab6a97b86d1a90dfd0352fe0e23537c3906a6ae1b54bbc3729934df53869c8a5ed5a14d30f153269dffcf6495dc34fd2800a994752820000a0017000b800298b46fda5892a8eb10649cbf4a536a12b585ee3a0d20d25f5f95352398ac4c697ec938ec4153064dda9679e6df583fd60f0d023433d5c7", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "88e30f0d83642f336c96df697e94034a681d8a08007940b971b66e05d53168df0f13890880d38d3edbee8000768bca54a7d7f4e2e15c4e7f7f4084f2b124ab04414b414d588ca47e561cc5819085f7d969df6496e4593e94640a6a22541002ca816ee34cdc138a62d1bfcff97f0b93b6ecd8cd4f77fc4f93c1edd76e6f4886186083e7e8", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "8b5f911d75d0620d263d4c795ba0fb8d04b0d5a7e86c96d07abe940bca65b6a504008940b37022b8dbaa62d1bf52848fd24a8f0f138efe4b1b8c902d36d3521240dc07f3eb768dd06258741e54ad9326e61d5c1f4089f2b567f05b0b22d1fa868776b5f4e0df0f0d8313edb7d57f1388ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "89be", + "headers": [ + { + ":status": "204" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "seqno": 123, + "wire": "887684aa6355e7d7f3d0bf4088ea52d6b0e83772ff8749a929ed4c02076496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37febe17f11d2acf4189eac2cb07f33a535dc618f1e3c2e6a6cf07b2893c1a42ae43d2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a9a725f535ee85486fe853570daa64d37d4e1a7229a61e2a5ed5a3f9f", + "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\"" + } + ] + }, + { + "seqno": 124, + "wire": "88d7f658a1aec3771a4bf4a547588324e5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfed6496c361be94034a436cca05f75e5022b8005c0014c5a37f0f0d023335dc76025153", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "880f0d023335f46c96e4593e941054ca3a941000d2817ee361b8c814c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196df3dbf4a002a693f7504008940b571905c03ea62d1bf6496e4593e940bea435d8a080002810dc699b800298b46ff5f87352398ac4c697ffa55850b8f09b07f58a9aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52bb0fe7d2d617b8e83483497f7686c58703025c1ff7", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "88c30f0d023335c4f7c2c5c1bfc0be", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "89c17b8b84842d695b05443c86aa6f5a839bd9abfbe70f0d0130cffaf9", + "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" + } + ] + } + ], + "description": "Encoded by nghttp2. The basic encoding strategy is described in http://lists.w3.org/Archives/Public/ietf-http-wg/2013JulSep/1135.html We use huffman encoding only if it produces strictly shorter byte string than original. We make some headers not indexing at all, but this does not always result in less bits on the wire." +} \ No newline at end of file diff --git a/http/http-client/src/test/resources/hpack-test-case/story_29.json b/http/http-client/src/test/resources/hpack-test-case/story_29.json new file mode 100644 index 0000000000..29839fd0d8 --- /dev/null +++ b/http/http-client/src/test/resources/hpack-test-case/story_29.json @@ -0,0 +1,14450 @@ +{ + "cases": [ + { + "seqno": 0, + "wire": "488264015f92497ca589d34d1f6a1271d882a60e1bf0acf70f1f8f9d29aee30c78f1e17a5152e43d2c7f768dd06258741e54ad9326e61d5dbf4089f2b567f05b0b22d1fa868776b5f4e0df6196dc34fd280654d27eea0801128166e09fb82754c5a37f0f0d820b42", + "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" + } + ] + }, + { + "seqno": 1, + "wire": "88588da8eb10649cbf4a54759093d85f4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5a839bd9ab7b8b84842d695b05443c86aa6f4003703370afbdae0fe74ead2a70d3914bdab429a61e2a6edf0a99f55e52f70da352fe0e23535ee846a6bdd7c6a6ae1b54c9a6fff30f28d0ddb6f63e1bb6c10f0dfab6e0bf936c00f8c583571876c1f17f55d804008821033f6a17cd66b0a88341eafa500cada4fdd61002d28166e09fb827d4c5a37fda921e919aa817a5152e43d3f6a5634cf031408a2d961ec21e4290f6d49f055b303a305d4001738bbda99dd7b180200080100740892c9315621ea4d87a3f86a8eb2127b0bf6196dc34fd280654d27eea0801128166e09fb82794c5a37f0f0d84682e34f7", + "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" + } + ] + }, + { + "seqno": 2, + "wire": "88588aa47e561cc581a644007f5f87352398ac4c697f52848fd24a8f0f138efe5e03c49472b2408c8f06e03f9fcdcc7f06a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f0d023433558375975a6196dc34fd280654d27eea0801128166e09fb827d4c5a37f6c96d07abe9413ea6a22541000ea816ee005702ca98b46ff6496dc34fd280654d27eea0801128266e09cb8cb6a62d1bf408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 3, + "wire": "88588fa47e561cc581e71a003eabb63a0c4fc6c50f138efe40ebd21650b240ca4903701fcf768abda83a35ebddbef42077d4c50f0d02343355846596442fc46c96c361be94101486bb14100225041b8c86e09e53168dff6496dd6d5f4a01a5349fba820044a01ab816ae01d53168dfc3", + "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" + } + ] + }, + { + "seqno": 4, + "wire": "88588ca47e561cc58190b6cb80003fcbca0f138efe40f3324af3f1b918c8f06e03f9768abb9f868d7af76fbd081ed9ca0f0d83085c1755867d979e13cd7fc96c96df697e941014d03f4a0800794102e05db8cb4a62d1bf6496e4593e940baa65b6850400b2a0837197ae01b53168dfc8", + "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" + } + ] + }, + { + "seqno": 5, + "wire": "88c7cfce0f138efe40ebd21650b240ca4903701fcfc6dccd0f0d023433c5cbc4c3c8", + "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" + } + ] + }, + { + "seqno": 6, + "wire": "88c2cfce0f138dfe40fb91b2f4817c840dc07f3fc6dccd0f0d033431375586085c6da700dfcc6c96df697e94032a681fa50400854102e322b82794c5a37f6496c361be941054cb6d4a08016540b9700e5c034a62d1bfcb", + "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" + } + ] + }, + { + "seqno": 7, + "wire": "88588aa47e561cc581c034f001d3d20f138ffe5f7dd79f95f94651bc4903701fcf768abda83a35ebddbef42073e1d27f198abda83a35ebddbef420730f0d8313a117558565d79f681fd26c96c361be940894d444a820044a05fb8205c1054c5a37ff6496df697e94038a693f750400894035702cdc69f53168dfd1", + "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" + } + ] + }, + { + "seqno": 8, + "wire": "88c35f88352398ac74acb37fd80f138ffe647248df75f75c2c6f9240dc07f3768abda83a35ebddbef4206fe7d87f048abda83a35ebddbef4206f0f0d83644e0b558465d7c0efd86c96dc34fd280654d27eea0801128015c6dab8d814c5a37f6496dc34fd281029a4fdd4100225002b8dbb71a1298b46ffd7", + "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" + } + ] + }, + { + "seqno": 9, + "wire": "88c9c3dd0f138ffe5c2086fc8d85d04612481b80fe7fc2ebdcc10f0d8369c69e5584132e3ccfdb6c96df697e94132a6a2254100225042b8d3b700253168dff6496dc34fd281029a4fdd410022500e5c6dab8d36a62d1bfda", + "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" + } + ] + }, + { + "seqno": 10, + "wire": "88d45f89352398ac7958c43d5fe10f138dfe40f884e361959789186e03f9ccefe00f0d83684f3955867d979e13efffdf6c96df697e94081486d994100205000b8066e000a62d1bff6496e4593e940baa65b6850400b2a08371976e36053168dfde", + "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" + } + ] + }, + { + "seqno": 11, + "wire": "88d0cae40f138ffe657e579f0351b638df2481b80fe7cff2e3ce0f0d836996c5558469c0b61fe26c96dc34fd280654d27eea0801128005c13f7191298b46ff6496dc34fd281029a4fdd4100225000b8d02e05e53168dffe1", + "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" + } + ] + }, + { + "seqno": 12, + "wire": "88d3cde70f138ffe5e699744e32479f8de2481b80fe7ccf5e6cb0f0d83702c875584132c859fe56c96df3dbf4a002a693f75040089413371966e004a62d1bf6496dc34fd281029a4fdd410022500edc002e36e298b46ffe4", + "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" + } + ] + }, + { + "seqno": 13, + "wire": "88d6d0ea0f138ffe5b686e342205a7a37c9206e03f9f768abda83a35ebddbef4207bf9ea7f108abda83a35ebddbef4207b0f0d836db10b5584132c81afea6c96c361be940094d27eea0801128215c13371b7d4c5a37f6496dc34fd281029a4fdd410022500edc006e01b53168dffe9", + "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" + } + ] + }, + { + "seqno": 14, + "wire": "88dbd5ef0f138ffe656e476572571e8de2481b80fe7fd4fdeed30f0d83680d3d5584132c89cfed6c96df3dbf4a002a693f7504008940bf7197ae05b53168df6496dc34fd281029a4fdd410022500edc002e34ca98b46ffec", + "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" + } + ] + }, + { + "seqno": 15, + "wire": "88ded8f20f138efe5d79f784dc6cc6e3c4206e03f9c5ff01f10f0d83740eb75585640d38f87ff06c96e4593e94642a436cca08010a817ae09db8db4a62d1bf6496e4593e9403aa693f750400894002e361b81794c5a37fef", + "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" + } + ] + }, + { + "seqno": 16, + "wire": "88e15f87352398ac5754dff60f138ffe5c1b4e05e91e6491be4903701fcfe14089f2b567f05b0b22d1fa868776b5f4e0dff6e10f0d84085b69af55846df03ceff56c96c361be940094d27eea0801128205c6deb8d32a62d1bf6496c361be9403ea693f750400894106e01ab8d094c5a37ff4", + "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" + } + ] + }, + { + "seqno": 17, + "wire": "88e6e0fa0f138ffe42f3d23ee848cb91be4903701fcfcdc1f9cc0f0d8365d6d9c8f76c96c361be940094d27eea0801128205c082e32253168dffc7f5", + "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" + } + ] + }, + { + "seqno": 18, + "wire": "88e7fcfb0f138efe5e00df134c8e51bc4903701fcfe0c2fadf0f0d8310596f558471a7dc77f96c96c361be940894d444a820044a05fb826ae36ea98b46ff6496c361be9403ea693f7504008940bf704e5c684a62d1bff8", + "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" + } + ] + }, + { + "seqno": 19, + "wire": "88eae4fe0f138ffe64189b7c6e0072c6f9240dc07f3fe9c5fde80f0d8371d79c55837df703fc6c96dc34fd280654d27eea0801128105c65eb8cb6a62d1bf6496dc34fd281029a4fdd4100225020b8d33704f298b46fffb", + "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" + } + ] + }, + { + "seqno": 20, + "wire": "88ede7ff020f138ffe5918a396475c6de8df2481b80fe7f9c8ff017f148abda83a35ebddbef420770f0d8371e6df558469d69c6bff016c96dc34fd280654d27eea0801128005c0b9704e298b46ff6496dc34fd281029a4fdd4100225000b817ae09b53168dffff00", + "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" + } + ] + }, + { + "seqno": 21, + "wire": "88f1eb52848fd24a8f0f138efe652965195e6871be4903701fcffecd4003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3fc30f0d83740e39d86196dc34fd280654d27eea0801128166e09fb827d4c5a37f6c96c361be940094d27eea0801128215c65fb82654c5a37fd8408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 22, + "wire": "88f6f0c20f138ffe5a8c31beec8420237c9206e03f9ff5d1c1f40f0d840b4f89ef5583138eb9c16c96dc34fd280654d27eea0801128115c699b8d34a62d1bf6496dc34fd281029a4fdd4100225022b8d3571b654c5a37fc1", + "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" + } + ] + }, + { + "seqno": 23, + "wire": "88ff025f86497ca582211f5a839bd9abc70f138ffe5e04ac85a24a1763749206e03f9f7b8b84842d695b05443c86aa6f768abda83a35ebddbef42077d8c80f0d84132f38d7558513e079c73fc86c96e4593e94642a6a225410022500cdc13d7196d4c5a37f6496df3dbf4a321535112a080165403571a0dc69953168dfc8", + "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" + } + ] + }, + { + "seqno": 24, + "wire": "88ff01facc0f138ffe5f23a190427c6cc6f9240dc07f3fff00dbcbfe0f0d8375a7dd55840b4e3c1fcb6c96dc34fd280654d27eea080112807ee043700fa98b46ff6496dc34fd281029a4fdd410022500fdc13571a794c5a37fcb", + "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" + } + ] + }, + { + "seqno": 25, + "wire": "885888a47e561cc58190035f87352398ac4c697f6c96c361be94036a6a225410022502fdc13f704f298b46ffd20f138efe401232dc6414a3649206e03f9f768dd06258741e54ad9326e61d5dbf54012ad36196dc34fd280654d27eea0801128166e09fb8c814c5a37f0f0d023432", + "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" + } + ] + }, + { + "seqno": 26, + "wire": "88588aa47e561cc581a644007f5f911d75d0620d263d4c795ba0fb8d04b0d5a7d70f138ffe5f0b6f3cf0431c6f464903701fcfc2e6d60f0d83134207558468200bbfc16c96e4593e94036a6e2d6a0801128266e01cb82654c5a37f6496dc34fd280654d27eea080112816ae01bb8db2a62d1bfd6d1d0", + "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" + } + ] + }, + { + "seqno": 27, + "wire": "88588ca47e561cc58190b6cb80003f5f88352398ac74acb37fd3dc0f138efe40569f923291b1949186e03f9fd2f7ebdb0f0d83680f0b558579c0b6eb81c66c96c361be9403aa651d4a08010a8266e361b80694c5a37f6496c361be94138a65b6850400b2a081702cdc13ea62d1bfdb", + "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" + } + ] + }, + { + "seqno": 28, + "wire": "88588aa47e561cc581c034f001cde00f138efe4640b8e3d1ca46c44186e03f9ffbefdffa0f0d0336353755850b6fb2d3dfca6c96df3dbf4a084a6a22541000fa807ee34e5c65b53168df6496df3dbf4a01e5349fba820044a05db8166e34253168dfdf", + "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" + } + ] + }, + { + "seqno": 29, + "wire": "88c6cae30f138ffe5e03238df18da71919240dc07f3fd8f2e20f0d84134e320f55867d979e13eeffcd6c96c361be94136a681fa5040089403b702fdc036a62d1bf6496e4593e940baa65b6850400b2a08371976e36ca98b46fe2dddc", + "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" + } + ] + }, + { + "seqno": 30, + "wire": "88c9cde60f138efe4028e58dc189f8dd2481b80fe7768abda83a35ebddbef4206ff6e60f0d8471b71d07558513cdbc107fd16c96e4593e94642a6a225410022500ddc65ab8cbca62d1bf6496df3dbf4a321535112a0801654039700e5c0014c5a37fe6e1e0", + "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" + } + ] + }, + { + "seqno": 31, + "wire": "88cdd7e1ea0f138efe5e048f3c37da71919240dc07f3e0dff9e90f0d0237345585780ebaf89bd46c96c361be94136a681fa5040089403b702fdc032a62d1bf6496c361be94009486d9941002ca800dc65db826d4c5a37fe9", + "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" + } + ] + }, + { + "seqno": 32, + "wire": "88d0daed0f138ffe5e03eec8ebef34e3232481b80fe7e2fcec0f0d02343855867d979f75c6ffd76c96c361be94136a681fa5040089403b702f5c65b53168df6496e4593e940baa65b6850400b2a083702cdc136a62d1bfec", + "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" + } + ] + }, + { + "seqno": 33, + "wire": "88d3ff01e7f00f138ffe5b8c8cc92c810bb1ba4903701fcfe6768abda83a35ebddbef42073ff01f00f0d83704cb5558513e079c77fdb6c96e4593e94642a6a225410022500cdc13d7197d4c5a37fe5ef", + "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" + } + ] + }, + { + "seqno": 34, + "wire": "88d6e0f30f138ffe5e004ae46f91a71919240dc07f3fe84089f2b567f05b0b22d1fa868776b5f4e0dff30f0d830842ef558579c0b4165fde6c96c361be94136a681fa5040089403b702f5c682a62d1bf6496c361be94138a65b6850400b2a08171a05c642a62d1bff3", + "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" + } + ] + }, + { + "seqno": 35, + "wire": "88dae4f70f138efe40eba5946f34e3232481b80fe7768abda83a35ebddbef4207bc2f70f0d0234335586085b75a7dc6fe26c96c361be94136a681fa5040089403b702fdc0094c5a37f6496dc34fd28212996da941002ca816ae059b826d4c5a37ff7", + "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" + } + ] + }, + { + "seqno": 36, + "wire": "88dee8fb0f138ffe5e03eec8ebef34e3232481b80fe7c8c5fa0f0d83085a1755857d979e6400e5cb6496e4593e940baa65b6850400b2a08371976e36053168dff9", + "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" + } + ] + }, + { + "seqno": 37, + "wire": "88e0eafd0f138ffe5e03ce4ad0db69c6464903701fcfcac7fc0f0d820ba2bfe66c96c361be94136a681fa5040089403b702f5c6dd53168dfbffa", + "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" + } + ] + }, + { + "seqno": 38, + "wire": "88e1e5fe0f138ffe5e005c95d1bad15c74840dc07f3ff3c8fd0f0d826841cee76c96df697e94640a436cca08010a817ee36d5c682a62d1bfcdfbf6f5", + "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" + } + ] + }, + { + "seqno": 39, + "wire": "88e25f87352398ac5754dfff010f138efe5f1ba3944cba58db2481b80fe7f5caff000f0d836da65c558569c109e77fea6c96d07abe9413ea6a2254100225002b8cb7702053168dff6496df697e9413ea6a22541002ca806ee01ab8d32a62d1bfff00", + "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" + } + ] + }, + { + "seqno": 40, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3dff152848fd24a8f0f138efe401232dc6414a3649206e03f9ff1f04003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f6196dc34fd280654d27eea0801128166e09fb827d4c5a37f0f0d830b8d034085aec1cd48ff86a8eb10649cbf408a224a7aaa4ad416a9933f8365f79f6496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd61009c65d640b6f0800dbedb8f816bcd000000000000010b4203d5a839bd9ab", + "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" + } + ] + }, + { + "seqno": 41, + "wire": "88588da8eb10649cbf4a54759093d85fc35f92497ca589d34d1f6a1271d882a60b532acf7fc07b8b84842d695b05443c86aa6f7f08afbdae0fe74ead2a70d3914bdab429a61e2a6edf0a99f55e52f70da352fe0e23535ee846a6bdd7c6a6ae1b54c9a6fff30f28cdddb6f63bf068dd009b69c744ffc5f804db4e3a27fe21c3069d58756dd1f6a17cd66b0a88341eafa500cada4fdd61002d28166e09fb8c814c5a37fda921e919aa817a5152e43d3f6a5634cf031f408a2d961ec21e4290f6d49f055b303a305d4001738cbda99dd7b180200b2c800fff40892c9315621ea4d87a3f86a8eb2127b0bfca0f0d83105f77", + "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" + } + ] + }, + { + "seqno": 42, + "wire": "4882640258a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bfcb0f1fff339d29aee30c1171a64a52b90f4b045e634bfe5b21204d9697e24340cb40f8acd03ac85df8ad103ed8401f8a2a9a02d4b5a8f84d704e94d6ab30aa2c2a8b0f8f1e17a5152e43d2a8b0c859476d09f15959f0b8d15f9f8b0d2405644268242099095a109c8df0b6d3240b6d492331ba5f8b2a9200b2d85f69f65d0004cfc592c1f08259005971cf2eb8f7c6d2c97a022f4a2a5c87a7e347e61db0337dc64575bbadb2db8e005759704d8b0b6e36eb6e380c177f768dd06258741e54ad9326e61d5dbfe1ce0f28d3d1c325f819bee322baddd6d96dc7002bacb826c585b71b75b71c060bbf1bf864bf007ed490f48cd540bd28a9721e9fb50be6b3585441a0f57d280656d27eeb08016940b3704fdc640a62d1bfed4ac699e063efff010f0d0130", + "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" + } + ] + }, + { + "seqno": 43, + "wire": "885886a8eb2127b0bf0f0d0234325f87352398ac4c697f5d9a9d29aee30c22b2ae34c94a5721e960d48e62a18acde4b42f31a5640130d1408721eaa8a4498f57842507417f", + "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" + } + ] + }, + { + "seqno": 44, + "wire": "c50f0d01306196dc34fd280654d27eea0801128166e09fb8c814c5a37f0f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c32e342640db01583e42bcc6975886a8eb10649cbfd37686c58703025c1f5f92497ca589d34d1f6a1271d882a60e1bf0acf7", + "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" + } + ] + }, + { + "seqno": 45, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd6c664022d316c96d07abe940bca65b68504008540bf700cdc65d53168dfdb0f138ffe4627d913ae38ec8d364206e03f9fca7f0f8be393068dda78e800020007c50f0d023432", + "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" + } + ] + }, + { + "seqno": 46, + "wire": "885889a47e561cc5802f001f5f8b497ca58e83ee3412c3569fd7de0f138efe40279d90b23b2c6f9240dc07f3d4768dd06258741e54ad9326e61d5c1f54012a0f0d830bc10f55830bae37ca6c96dc34fd280654d27eea080112806ae36f5c6dc53168df6496dc34fd280654d27eea0801128166e320b80694c5a37f7f0e88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 47, + "wire": "88c5c4dde40f138efe5e03a210dd201f78840dc07f3fdac3c20f0d837d969c5583085d07ce6c96df697e940054d27eea08010a817ae01ab807d4c5a37f6496dc34fd280654d27eea0801128166e340b800298b46ffc1", + "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" + } + ] + }, + { + "seqno": 48, + "wire": "88c8c7e0e70f138efe403959786d900fbc4206e03f9fddc6c50f0d84101e03df55830b410fd16c96df697e940054d27eea08010a817ae01ab80714c5a37f6496dc34fd280654d27eea0801128166e32ddc6df53168dfc4", + "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" + } + ] + }, + { + "seqno": 49, + "wire": "88cbcae3ea0f138ffe5e03e12b4523b2c6f9240dc07f3fe0c9c80f0d83085a1755830884e7d46c96dc34fd280654d27eea080112806ae36f5c6db53168df6496dc34fd280654d27eea0801128166e32fdc034a62d1bfc7", + "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" + } + ] + }, + { + "seqno": 50, + "wire": "deddea0f1fff349d29aee30c117a5152e43d2c11798d2ff96c8481365a5f890d032d03e2b340eb2177e2b440fb61007e28aa680b52d6a3e135c13a535aacc2a8b0aa2c3e3c785e9454b90f4aa2c321651db427c56567c2e3457e7e2c3490159109a09082642568427237c2db4c902db5248cc6e97e2caa4802cb617da7d97400133f164b07c209640165c73cbae3df1a3864bf032fde0bcd3376fbb7aeb8ebf800e099780cb97dabd75c74177e091c012491be475a0b426de8c1dcff00ec0f28d0ddb7445a2065fbc179a66edf76f5d71d7f001c132f01972fb57aeb8e82efda921e919aa808b8d325295c87a7ed42f9acd61510683d5f4a0195b49fbac2005a502cdc13f7190298b46ffb52b1a67818fbd60f0d0130", + "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" + } + ] + }, + { + "seqno": 51, + "wire": "88ddeada6c96df3dbf4a080a6a2254100215020b8276e36f298b46ffee0f138efe40d4631965089e94840dc07f3fddff01ed0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7fd70f0d023432", + "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" + } + ] + }, + { + "seqno": 52, + "wire": "88cf5f88352398ac74acb37fe8ef0f138efe44fbe37851c858df2481b80fe7e5cecd0f0d841000d39f5583081d6bd96c96c361be940094d27eea080112816ee09eb8d094c5a37f6496dc34fd280654d27eea0801128166e341b8cb8a62d1bfcc", + "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" + } + ] + }, + { + "seqno": 53, + "wire": "890f0d0130dbccef6496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf", + "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" + } + ] + }, + { + "seqno": 54, + "wire": "88e16c96c361be940baa436cca080112816ae09db8db6a62d1bf6196c361be940094d27eea080112817ee32d5c6de53168df6496dc34fd280654d27eea080112817ee32d5c6de53168df4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d023436408cf2b794216aec3a4a4498f57f8a0fda949e42c11d07275f558471a69d675890aed8e8313e94a47e561cc581e71a003f", + "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" + } + ] + }, + { + "seqno": 55, + "wire": "886196dc34fd280654d27eea0801128076e001704ca98b46ff768bca54a7d7f4e2e15c42feff7f34cdacf4189eac2cb07f2c78648c567a0c4f4bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a97b86d1a90dfd0352fe0e23537c3906a6ae1b54bbc3729934df53869c8a5ed5a14d30f153269dffcffe7ec4089f2b567f05b0b22d1fa90d06b2c3d8a64a473154c9524b65454ff7c950ae152394c07020034a7f5a32645a1d779812e2fef408bf2b52632c419272ad3993f01310f0d0234324088ea52d6b0e83772ff8649a929ed4c027f1e88cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 56, + "wire": "88588ca47e561cc58190b6cb80003ff2fe52848fd24a8f0f138efe405132d3e569c6464903701fcffc768abda83a35ebddbef420777f06868776b5f4e0df7f08a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f0d0239335585780ebaf89c6196dc34fd280654d27eea0801128166e09fb8c854c5a37f6c96c361be94136a681fa5040089403b702f5c69a53168df6496c361be94009486d9941002ca800dc65db826d4c5a37fe7", + "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" + } + ] + }, + { + "seqno": 57, + "wire": "88768c86b19272ad78fe8e92b015c30f28e5aed9298a1861860d19edf246adc70e16f1e0a248529d3fee9dfa31b7433c309314bd39c3df46ee9a3478bfcb5b3beff0e5407ed4be7a466aa05ec2f7410cbd454fda983cd66b0a88375b57d280656d27eeb08016540b3704fdc642a62d1bfed4d634cf031ff64085aec1cd48ff86a8eb10649cbf6496df3dbf4a002a651d4a05f740a0017000b800298b46ff7f06e9acf4189eac2cb07f33a535dc618e885ec2f7410cbd454b1e19231620d5b35afe69a3f9fa52f6b83f9d3ab4a9af742a6bdd7d4c9c6153271bea6adfad4dd0e853269bea70d3914d7c36a97b568534c3c54c9a77a97f06852f69dea6edf0a9af6e05356fbca63c10ff3f4088f2b5761c8b48348f89ae46568e61a002581f5f9e1d75d0620d263d4c741f71a0961ab4fd9271d882a60c9bb52cf3cdbeb07f798624f6d5d4b27f5a839bd9ab7b8b84842d695b05443c86aa6f6196dc34fd280654d27eea0801128166e09fb8c814c5a37f", + "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" + } + ] + }, + { + "seqno": 58, + "wire": "88588da8eb10649cbf4a54759093d85fc75f92497ca589d34d1f6a1271d882a60b532acf7fc2c17f07afbdae0fe74ead2a70d3914bdab429a61e2a6edf0a99f55e52f70da352fe0e23535ee846a6bdd7c6a6ae1b54c9a6fff30f28d1ddb6f63bf06ed1007e346e804db4e3a27fe2fc026da71d13ff10e1834eac3ab6e8fb50be6b3585441a0f57d280656d27eeb08016940b3704fdc642a62d1bfed490f48cd540bd28a9721e9fb52b1a67818f408a2d961ec21e4290f6d49f055b303a305d7f3e8bbda99dd7b180200880113d40892c9315621ea4d87a3f86a8eb2127b0bfc40f0d830b8e8b", + "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" + } + ] + }, + { + "seqno": 59, + "wire": "88d65f911d75d0620d263d4c795ba0fb8d04b0d5a7d60f138efe403684018da71919240dc07f3f768abda83a35ebddbef42073d5d40f0d033338375586085c6da7422fd36c96c361be94136a681fa5040089403b702fdc034a62d1bf6496c361be941054cb6d4a08016540b9700d5c0bea62d1bffccbca", + "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" + } + ] + }, + { + "seqno": 60, + "wire": "88dbf1cbda0f138efe40dc630be369c6464903701fcfcac1d8d70f0d8369e6855586085c6da6dd176196dc34fd280654d27eea0801128166e09fb8c894c5a37f6c96c361be94136a681fa5040089403b702f5c65e53168df6496c361be941054cb6d4a08016540b9700e5c680a62d1bf7f2188ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 61, + "wire": "88e05f87352398ac4c697fe00f138ffe5e046c89b1bad38c8c9206e03f9fc7dedd0f0d830840df558579c0b41683c36c96c361be94136a681fa5040089403b702f5c6df53168df6496c361be94138a65b6850400b2a08171a05c642a62d1bfc2", + "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" + } + ] + }, + { + "seqno": 62, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffe60f138efe401232dc6414a3649206e03f9f768dd06258741e54ad9326e61d5dbf54012ae5ca0f0d03353632df408a224a7aaa4ad416a9933f033838346496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9cd61038e3ec85e5b784006df6de6995af040f000000000000216dd10bdc", + "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" + } + ] + }, + { + "seqno": 63, + "wire": "88c5e27f018364216bc5c0c37f009cd61038065a034b6f0800dbedbadb8b5e69e00000000000042cb4f35fc3eae8de0f0d830b2267", + "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" + } + ] + }, + { + "seqno": 64, + "wire": "88c7c6c5ed0f138efe401232dc6414a3649206e03f9fc4c3eae80f0d830b2cb9e47f0083642d3bc27f009cd6103a2036d36b6f0800dbedbecbeb5e6c4000000000000880dbef7fe0", + "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" + } + ] + }, + { + "seqno": 65, + "wire": "88c9e67f0003343036c9c4c77f0094d6cbaf09f69a5b784006de13acbeb5e6c41138cfc7eeece20f0d03333235", + "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" + } + ] + }, + { + "seqno": 66, + "wire": "88f2cff10f138dfe411c8d85a942d0c8c86e03f9c8efee0f0d0238355586089e7da13aefd46c97df697e940b6a65b685040032a05cb8d3f719794c5a37ff6497c361be9403aa65b6a50400b2a01db8d3571b6d4c5a37ffd3e5e4", + "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" + } + ] + }, + { + "seqno": 67, + "wire": "885892aed8e8313e94a47e561cc58190b6cb6fbeffd3cc408cf2b0d15d454addcb620c7abf8769702ec8190bfff40f0d8313a107558665c6df65d07fd96496dd6d5f4a084a6e2d6a08016540377000b800a98b46ffd7", + "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" + } + ] + }, + { + "seqno": 68, + "wire": "885892aed8e8313e94a47e561cc58190b60782f3ff5f88352398ac74acb37fd1c2f80f0d837c4207558665c6df65b7bfdd6496dc34fd2820a9b8b5a8200595041b8172e34ca98b46ffdb", + "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" + } + ] + }, + { + "seqno": 69, + "wire": "885892aed8e8313e94a47e561cc58190b2cbc075dfc1d4c5fb0f0d8365c03b558565a000220fe06496dd6d5f4a084a6e2d6a080165410ae005700f298b46ffde", + "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" + } + ] + }, + { + "seqno": 70, + "wire": "886c96c361be940094d27eea080112807ee32ddc65953168df0f139afe42d042fbefbcf352b417ca378417e395f8db64237c8e39fcff52848fd24a8f5f9a1d75d0620d263d4c741f71a0961ab4fda849c7620a982d4cab3df2f30f0d83644e03e4e17f2fc6bdae0fe6f43a94bfbb5a99e1e4a5ee1b46a437f40d4bf8388d4df0e41a9af7423535eebe353271846a64e37c6a6ae1b54bbc3729934df53869c8a5ed5a14d30f153269dffcff", + "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\"" + } + ] + }, + { + "seqno": 71, + "wire": "885f961d75d0620d263d4c7441eafb50938ec415305a99567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb0f0d023335e7e4", + "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" + } + ] + }, + { + "seqno": 72, + "wire": "880f13a1fe5975d904dbb28a41144fb4f85c0b4c900e3e16824091bb81644f3acbc10b5fcf6c96e4593e9403ca612c6a080112820dc6dbb81694c5a37fc30f0d023433e45886a8eb10649cbfc2e9e6", + "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" + } + ] + }, + { + "seqno": 73, + "wire": "886c96dc34fd280654d27eea0801128166e04171b1298b46ff4085aec1cd48ff86a8eb10649cbf408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fc3408442469b51851000a6acdf5f9a1d75d0620d263d4c741f71a0961ab4fd9271d882a60b532acf7ffd0f0d0338383976824ca5fd58ada8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd2959d095893949d6007d295d855893949d6007f6496dc34fd280654d27eea0801128166e09fb8c894c5a37ff1ee", + "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" + } + ] + }, + { + "seqno": 74, + "wire": "88ed4089f2b26c1d48191263d58c69f925684ecaeb4c95b7647b6c96dc34fd280654d27eea0801128166e09fb8c894c5a37f6496df697e94642a681d8a05f782a01bb8005c0014c5a37fc758ada8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd295d855893949d6007d2959d095893949d6007f0f28c99ad2a1311a483b8556610b2d85f69f65d136ebac85b71cfb53079acd61510683d5f4a32b693f758400b4a059b827ee32253168dff6a6b1a67818fb52f9e919aa8174f832525b1721e9f55a839bd9ab0f0d023635c5", + "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" + } + ] + }, + { + "seqno": 75, + "wire": "886c96c361be940094d27eea080112807ee34f5c0b2a62d1bf0f139afe63032e0dd7c2f042596523ee3d1ca48da6651b9238f841fcffd25f92497ca589d34d1f6a1271d882a60b532acf7f7b8b84842d695b05443c86aa6fc10f0d83744d0bf9f6d2588faed8e8313e94a47e561cc5802f001f", + "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" + } + ] + }, + { + "seqno": 76, + "wire": "886196dc34fd280654d27eea0801128166e09fb8cb4a62d1bf768586b19272ff6c96dc34fd280654d27eea0801128172e09eb82714c5a37f6496e4593e9403aa693f7504008940b9704f5c138a62d1bf0f139d6822109a859132d6079e844eb8069c79965913a1004176e86f397c30c358a5a47e561cc58196db7590fd576c74189f551d64d83a9129eca7ea9b5095ac2f71d0690692ff408df2b1c88ad6b0b59ea90b62c693884bc5908339115b5f0f0d03343731408721eaa8a4498f57842507417f5f911d75d0620d263d4c1c88ad6b0a8acf520b", + "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" + } + ] + }, + { + "seqno": 77, + "wire": "88be409221ea496a4ac9b0752252d8b16a21e435537f85ba6a8767af0f0d830becbd7f0184bd41d05f", + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "Binary" + }, + { + "content-length": "1938" + }, + { + "connection": "Close" + } + ] + }, + { + "seqno": 78, + "wire": "88c7c6c5c40f139d6822109a859132d6079e844eb8069c79965913a1004176e86f397c30c3c3c20f0d03343731c1c0", + "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" + } + ] + }, + { + "seqno": 79, + "wire": "88588da8eb10649cbf4a54759093d85fd8cbcd64022d31cb768dd06258741e54ad9326e61e5c1f408ef2b0d15d454d3dc8b772d8831eaf03342e30408bf2b5a35887a6b1a4d1d05f8cc9820c124c5fb24f61e92c01e0dbef4089f2b567f05b0b22d1fa868776b5f4e0dfe16196dc34fd280654d27eea0801128166e09fb8cb6a62d1bf0f0d8413c00bdf", + "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" + } + ] + }, + { + "seqno": 80, + "wire": "886196dc34fd280654d27eea0801128072e34f5c6da53168df768bca54a7d7f4e2e15c42feff7f27cdacf4189eac2cb07f2c78648c567a0c4f4bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a97b86d1a90dfd0352fe0e23537c3906a6ae1b54bbc3729934df53869c8a5ed5a14d30f153269dffcffe35f87352398ac4c697f7f0490d06b2c3d8a64a473154c9524b65454ff7c950ae152394c070200054feb464c8b43aef3025c5fdf408bf2b52632c419272ad3993f01310f0d0234324088ea52d6b0e83772ff8649a929ed4c027f0e88cc52d6b4341bb97f", + "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" + } + ] + }, + { + "seqno": 81, + "wire": "88588ca47e561cc58190b6cb80003f5f86497ca582211fdef10f138ffe5e016324ad85b14602481b80fe7fdbcdcaed0f0d8371d0bb55850804e3817fca6c96d07abe941094d444a820044a0457197ee34ea98b46ff6496df697e941094d444a820059502e5c0bf702e298b46ff7f0488ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 82, + "wire": "88c35f901d75d0620d263d4c741f71a0961ab4ffe3f60f138efe4017db1c6db628c04903701fcfe0d2cff20f0d8379c6df55850804e38177cf6c96d07abe941094d444a820044a04571a15c65a53168dff6496df697e941094d444a820059502e5c0bf702f298b46ffc2", + "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" + } + ] + }, + { + "seqno": 83, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bff2ce6c96df3dbf4a080a6a2254100215020b8276e36f298b46fffb0f138efe40d4631965089e94840dc07f3f768dd06258741e54ad9326e61d5dbfd57f12a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7fd50f0d023432", + "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" + } + ] + }, + { + "seqno": 84, + "wire": "88cb5f87352398ac5754dfeb52848fd24a8f0f138ffe5d03a375a191b14602481b80fe7fe9dbd8fb0f0d837d979fc6d76c96d07abe941094d444a820044a04571a15c0bea62d1bffc5c9", + "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" + } + ] + }, + { + "seqno": 85, + "wire": "88cec0edbf0f138ffe6501641c6f46d8a301240dc07f3feadcd9fc0f0d8365d69f55850804e38d37d96c96d07abe941094d444a820044a04571a0dc134a62d1bff6496df697e941094d444a820059502e5c0bd71b0298b46ffcc", + "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" + } + ] + }, + { + "seqno": 86, + "wire": "88d1fb5f89352398ac7958c43d5ff1e1eee0dfde4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cbfc408cf2b0d15d454addcb620c7abf8769702ec8190bffdfbfde0f0d83684f396c96e4593e94642a6a225410022504cdc0b971b714c5a37fc60f138ffe5f6c2eb619051c91ba4903701fcf", + "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\"" + } + ] + }, + { + "seqno": 87, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692f4085aec1cd48ff86a8eb10649cbfdde66c96d07abe940bca65b68504008540bf700cdc65d53168dfc90f138ffe4627d913ae38ec8d364206e03f9fcc4001738be393068dda78e800020007e30f0d023432", + "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" + } + ] + }, + { + "seqno": 88, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7c3f5f88352398ac74acb37f768abda83a35ebddbef42077c6e7cf7f028abda83a35ebddbef420770f0d033737335585682e3aebbfe86496dc34fd280654d27eea0801128176e34cdc03ea62d1bfda", + "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" + } + ] + }, + { + "seqno": 89, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f79ffc3c2caebd3c10f0d8369d69d558471f7dd07eb6496e4593e9403aa693f7504008940bd700cdc0b4a62d1bfdd", + "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" + } + ] + }, + { + "seqno": 90, + "wire": "88cac9e8f1c8d30f138ffe4627d913ae38ec8d364206e03f9fd67f048be393068dda78e800020035ed0f0d023432", + "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" + } + ] + }, + { + "seqno": 91, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034265f0b9fc7768abda83a35ebddbef4206fcff0d87f018abda83a35ebddbef4206f0f0d8469b089bf558369d7c3f16496df3dbf4a01e5349fba820044a01fb8db7700053168dfe3", + "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" + } + ] + }, + { + "seqno": 92, + "wire": "885891aed8e8313ea91f95873160642db2e0000f0f0d846840701f5f911d75d0620d263d4c795ba0fb8d04b0d5a75a839bd9abdc0f138efe4232086595a70237c840dc07f37b8b84842d695b05443c86aa6ffa7f20dcbdae0fe61cf9d4c9a6fa97f76b52f6adaa437f4297b5693a97b86d52f70dc75327184ea64e37cea6bdd0a9af75f537c3914df8339d4d5c36a9ba1d0752f69dea5ed5a14c9a77a9a61e2a6ad39d4d78f9a9af6e0535f0daa70d393f9f4083ee91cd8d13afb8071c644d80000000007ff9558665f79d6de73f6196dc34fd280654d27eea0801128166e09fb8cb8a62d1bf6c96df697e941094d27eea08010a820dc6dfb80714c5a37f6496e4593e940bca6e2d6a080165403f71a7ee36053168dfed", + "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" + } + ] + }, + { + "seqno": 93, + "wire": "890f0d0130fcedd96496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bf", + "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" + } + ] + }, + { + "seqno": 94, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffe80f138efe401232dc6414a3649206e03f9feb54012aebc60f0d03393534df408a224a7aaa4ad416a9933f831000f76496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd6103a265a6995b784006db038fb2b5e13e0000000000003c27040ce", + "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" + } + ] + }, + { + "seqno": 95, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692ffe36496dc34fd2816d4d27eea08007940b97000b800298b46ff7f0fe6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f408cf2b794216aec3a4a4498f57f01300f28f61d5d20cd2db03d2e277ff9aef79b3cff6047ff3fe951678bfd7957760e2c4f565356d61d9c622e6e9fe3fd63083233bb76475f3f9feff8a317fe93ffcfb52b1a67818fb50be6b358544186c37d2800ad84b1ac20059502cdc13f719714c5a37fda921e919aa8171c957942e43d3f6a634a6bd5551ebf5f92497ca589d34d1f6a1271d882a60b532acf7fce0f0d03363135", + "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" + } + ] + }, + { + "seqno": 96, + "wire": "885886a8eb2127b0bf5f87497ca589d34d1fd5640130d56196dc34fd280654d27eea0801128166e09fb8cb6a62d1bf408721eaa8a4498f57842507417f0f0d03333831", + "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" + } + ] + }, + { + "seqno": 97, + "wire": "885f87352398ac4c697f0f0d02343256034745546496df697e94038a693f75040089403571b0dc6dc53168dfd67f0288ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 98, + "wire": "88cbf0cac9c80f28f61d5d20cd2db03d2e277ff9aef79b3cff6047ff3fe951678bfd7957760e2c4f565356d61d9c622e6e9fe3fd63083233bb76475f3f9feff8a317fe93ffcfb52b1a67818fb50be6b358544186c37d2800ad84b1ac20059502cdc13f719714c5a37fda921e919aa8171c957942e43d3f6a634a6bd5551ebf0f0d023433c1d7", + "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" + } + ] + }, + { + "seqno": 99, + "wire": "88c6c5dcc4db4086f2b5281c86938e640003cfb2f3ebb200004d38207fd8c30f0d83109f07", + "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" + } + ] + }, + { + "seqno": 100, + "wire": "88ed0f0d84680ebcffc16496df3dbf4a01e5349fba820044a08371b76e34053168df6196dc34fd280654d27eea0801128166e09fb8cbaa62d1bfc1", + "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" + } + ] + }, + { + "seqno": 101, + "wire": "88e00f0d84101e00bfc36496d07abe94036a693f75040089403971905c684a62d1bfbfc2", + "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" + } + ] + }, + { + "seqno": 102, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f71eff1e7f84089f2b567f05b0b22d1fa868776b5f4e0df7f10a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3fe80f0d836990bf55830ba077c36496df3dbf4a01e5349fba820044a059b8005c65e53168dfc7", + "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" + } + ] + }, + { + "seqno": 103, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85d701ff6f5408cf2b0d15d454addcb620c7abf8769702ec8190bffc3c2f50f0d836d910755840b4f899fc76496df3dbf4a01e5349fba820044a01fb8172e36d298b46fcb", + "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" + } + ] + }, + { + "seqno": 104, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7dcffa768abda83a35ebddbef42073c2c7c67f318abda83a35ebddbef420730f0d8369c037558469c65b7bcc6496df3dbf4a01e5349fba820044a00171972e36da98b46fd0", + "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" + } + ] + }, + { + "seqno": 105, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f137f5f88352398ac74acb37fc3c7cccbc20f0d83680fbb558471a65a6bd06496e4593e9403aa693f7504008940bf7196ee36f298b46fd4", + "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" + } + ] + }, + { + "seqno": 106, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c880007fc1c6cacfcec50f0d8369c7c55584644f361fd36496df3dbf4a01e5349fba820044a01ab8215c038a62d1bfd7", + "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" + } + ] + }, + { + "seqno": 107, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85d6dafc4c9cdd2d1c80f0d83136db755840b4f89afd66496df3dbf4a01e5349fba820044a01fb8172e34ea98b46fda", + "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" + } + ] + }, + { + "seqno": 108, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85d6defc7ccd0d5d4cb0f0d8368027355846da79f07d96496e4593e9403aa693f75040089410ae04171a6d4c5a37fdd", + "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" + } + ] + }, + { + "seqno": 109, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7ddfca768abda83a35ebddbef42077d4d9d87f108abda83a35ebddbef420770f0d8369b79f5585680c800effde6496dc34fd280654d27eea080112820dc64571a754c5a37fe2", + "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" + } + ] + }, + { + "seqno": 110, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7c1fcfc2d8dddcc10f0d8365a75c5584784113ffe16496e4593e9403aa693f7504008940b571a05c65e53168dfe5", + "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" + } + ] + }, + { + "seqno": 111, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85e65ffd2d7dbe0dfd60f0d836df13b55846d969b6fe46496e4593e9403aa693f75040089410ae32e5c0054c5a37fe8", + "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" + } + ] + }, + { + "seqno": 112, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7d9fd5768abda83a35ebddbef4207bdfe4e37f098abda83a35ebddbef4207b0f0d8369f003558479979977e96496e4593e9403aa693f7504008940b57022b81654c5a37fed", + "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" + } + ] + }, + { + "seqno": 113, + "wire": "88cdd9dee2e7e6dd0f0d8369a103558479e0381feb6496e4593e9403aa693f7504008940b37001b8db2a62d1bfef", + "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" + } + ] + }, + { + "seqno": 114, + "wire": "885f901d75d0620d263d4c1c892a56426c28e90f0d831080fff26496df3dbf4a01e5349fba820044a05fb8276e36da98b46feef1", + "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" + } + ] + }, + { + "seqno": 115, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f785fdec6e7ecebc50f0d836da7dc55847190ba0ff06496e4593e9403aa693f7504008940bf71b72e09f53168dff4", + "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" + } + ] + }, + { + "seqno": 116, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f7c3fe1c9eaefeec80f0d8365a6c1558479f6db6bf36496e4593e9403aa693f75040089408ae32e5c6da53168dff7", + "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" + } + ] + }, + { + "seqno": 117, + "wire": "88d2e3e8ecf1f0e70f0d83109d0f55847c4fb81ff56496e4593e9403aa693f750400894086e340b80714c5a37ff9", + "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" + } + ] + }, + { + "seqno": 118, + "wire": "88c2e5eaeef3f2e90f0d8368007f558479c642d7f76496e4593e9403aa693f7504008940b371905c6da53168dffb", + "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" + } + ] + }, + { + "seqno": 119, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f79ffe8768abda83a35ebddbef4206ff2f7f67f118abda83a35ebddbef4206f0f0d8365d75f558479c740f7fc6496e4593e9403aa693f7504008940b3704d5c0bca62d1bf408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 120, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f75cfeed6f7fcfbd50f0d8364216f558471f0bce76196dc34fd280654d27eea0801128166e09fb8cbaa62d1bf6496e4593e9403aa693f7504008940bd702e5c03aa62d1bfc2", + "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" + } + ] + }, + { + "seqno": 121, + "wire": "88e0f1e4fa4089f2b567f05b0b22d1fa868776b5f4e0df4003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3fe50f0d8369e71d5584780e09afc26496e4593e9403aa693f7504008940b7700ddc69953168dfc6", + "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" + } + ] + }, + { + "seqno": 122, + "wire": "88def5e8408cf2b0d15d454addcb620c7abf8769702ec8190bffc2c1e80f0d836c2f3b55850b40136cffc56496df697e94038a693f75040089410ae321b8dbaa62d1bfc9", + "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" + } + ] + }, + { + "seqno": 123, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f71cff9ecc1c5c4eb0f0d836c4d3555850b40782effc86496df697e94038a693f75040089410ae085700e298b46ffcc", + "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" + } + ] + }, + { + "seqno": 124, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f643ffcefc4c8c7ee0f0d8365e03b5585640cbeeb3fcb6496d07abe94036a693f750400894006e005702da98b46ffcf", + "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" + } + ] + }, + { + "seqno": 125, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f75df5f88352398ac74acb37f768abda83a35ebddbef42073c9cdcc7f168abda83a35ebddbef420730f0d83682cb755850b4cbccb7fd16496df697e94038a693f750400894106e321b8dbea62d1bfd5", + "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" + } + ] + }, + { + "seqno": 126, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f699fc3c2cdd1d0c10f0d836c0fb9558471a0b4ffd46496e4593e9403aa693f7504008940bf7197ee32153168dfd8", + "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" + } + ] + }, + { + "seqno": 127, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f79efc6f0d0d4d3ef0f0d8365e0075585089b13adffd76496e4593e9403aa693f75040089400ae341b8c814c5a37fdb", + "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" + } + ] + }, + { + "seqno": 128, + "wire": "88f9c8dfd2d6d5de0f0d8369a7df55850b4d05e17fd96496df697e94038a693f750400894106e09cb826d4c5a37fdd", + "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" + } + ] + }, + { + "seqno": 129, + "wire": "885f961d75d0620d263d4c7441eafb50938ec415305a99567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb0f0d023335dcdf", + "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" + } + ] + }, + { + "seqno": 130, + "wire": "88588da8eb10649cbf4a54759093d85f4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7f5a839bd9ab64022d317b8b84842d695b05443c86aa6f768dd06258741e54ad9326e61e5c1f408ef2b0d15d454d3dc8b772d8831eaf03342e30408bf2b5a35887a6b1a4d1d05f8cc9820c124c5fb24f61e92c01c7408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fe0e4c86196dc34fd280654d27eea0801128166e09fb8d094c5a37f0f0d84132d34ff", + "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" + } + ] + }, + { + "seqno": 131, + "wire": "88588ca47e561cc58190b6cb80003f5f86497ca582211fc752848fd24a8f0f138efe4129637db75b8c44903701fcffc6c5e8cc0f0d836df6855585742e81a6ffc26c96e4593e94134a6a225410022502e5c659b8d3ca62d1bf6496dc34fd282714d444a820059500e5c0bd71b754c5a37ff0", + "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" + } + ] + }, + { + "seqno": 132, + "wire": "88c35f901d75d0620d263d4c741f71a0961ab4ffccc20f138efe412bf2b2d34e4622481b80fe7fcac9ecd00f0d8379b13d5585742e81a6bfc66c96e4593e94134a6a225410022502e5c681704e298b46ff6496dc34fd282714d444a820059500e5c0bd71b794c5a37ff4", + "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" + } + ] + }, + { + "seqno": 133, + "wire": "88c75f87352398ac5754dfd0c60f138ffe5f71e1ba37db6c51809206e03f9fcecdf0d40f0d83782d3f55850804e38d87ca6c96d07abe941094d444a820044a04571a0dc680a62d1bff6496df697e941094d444a820059502e5c0bd71b0a98b46fff8", + "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" + } + ] + }, + { + "seqno": 134, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bfd65f87352398ac4c697f6c96df3dbf4a080a6a2254100215020b8276e36f298b46ffcc0f138efe40d4631965089e94840dc07f3f768dd06258741e54ad9326e61d5dbff7f60f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7fd00f0d023432", + "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" + } + ] + }, + { + "seqno": 135, + "wire": "88cfd95f89352398ac7958c43d5fd8d7d6d5d4d3dcd2f4f8dcd10f0d83684f396c96e4593e94642a6a225410022504cdc0b971b714c5a37fcf0f138ffe5f6c2eb619051c91ba4903701fcf", + "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\"" + } + ] + }, + { + "seqno": 136, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fdcc3d96c96d07abe940bca65b68504008540bf700cdc65d53168dfd10f138ffe4627d913ae38ec8d364206e03f9fc27f2c8be393068dda78e800020035d50f0d023432", + "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" + } + ] + }, + { + "seqno": 137, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffd50f138efe401232dc6414a3649206e03f9fc654012a4003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3fda0f0d03393534e3408a224a7aaa4ad416a9933f831000f76496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd6103a265a6995b784006db038fb2b5e13e0000000000003c27040e4", + "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" + } + ] + }, + { + "seqno": 138, + "wire": "88c8e6cde3c7da0f138ffe4627d913ae38ec8d364206e03f9fcb7f078be393068dda78e800020007de0f0d023432", + "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" + } + ] + }, + { + "seqno": 139, + "wire": "88588eaed8e8313e94a47e561cc5804d7f5f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559efe7ce4085a4649cd5178ddda43f3f3f3f3f3f3f3f2db22f4087b0b5485b126a4b8f085813020044a3d702d5c0b2a43a3f4089f2b567f05b0b22d1fa868776b5f4e0df0f0d8465a7dd0f55023339e46c96c361be940094d27eea080112816ee05ab81654c5a37f6496dc34fd280654d27eea0801128166e34d5c0094c5a37f408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 140, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692fff16496dc34fd2816d4d27eea08007940b97000b800298b46ff7f0ee6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f408cf2b794216aec3a4a4498f57f01300f28f91d5d20cd2db03d2e267cc17bcd9e7fb023ff9ff4a8b3c5febcabbb071627ab35afb58767188b9ba7f8ff58c20c8ceedd91db80f18fdffebfbc5fe7f666bf67cdf6a5634cf031f6a17cd66b0a8830d86fa50015b096358400b2a059b827ee34ca98b46ffb5243d2335502e392af285c87a7ed4c694d7aaaa3d7f36196dc34fd280654d27eea0801128166e09fb8d32a62d1bf0f0d03353134", + "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" + } + ] + }, + { + "seqno": 141, + "wire": "885891aed8e8313e94a47e561cc581d75d6da71d5f91497ca582211f6a1271d882a60b532acf7ff5dccbcac90f0d8413a2103f5585109c69f7ffc16c96e4593e94642a6a2254100225042b826ee36253168dff6496df697e9413ea651d4a080165410ae09bb8d854c5a37fc8408cf2b0d15d454addcb620c7abf8769702ec8190bff", + "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" + } + ] + }, + { + "seqno": 142, + "wire": "885885aed8e8313f0f0d830b4e37e8f0e1d87f008712e05db03a277fcf558475d69b07c76c96df3dbf4a01c53716b5040089403371a15c0b8a62d1bf6496c361be940b8a693f7504008940b771b7ae36d298b46fce", + "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" + } + ] + }, + { + "seqno": 143, + "wire": "885886a8eb2127b0bf5f87497ca589d34d1f5a839bd9ab6401307b8b84842d695b05443c86aa6f4086f2b5281c86938e640003cfb4d01713efbecb4f34f7cf7f15842507417f0f0d03353134", + "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" + } + ] + }, + { + "seqno": 144, + "wire": "88c95f88352398ac74acb37fede4c9da0f0d8365f65c55830b8e35d26c96df3dbf4a002a693f750400894086e36e5c684a62d1bf6496dc34fd280654d27eea080112816ae32ddc0054c5a37fd9", + "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" + } + ] + }, + { + "seqno": 145, + "wire": "88cdc1f0e7ccdd0f0d8369c69c55830b8db3d56c96c361be940094d27eea0801128015c685704d298b46ff6496dc34fd280654d27eea0801128176e05ab8d014c5a37fdc", + "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" + } + ] + }, + { + "seqno": 146, + "wire": "88c40f0d840b4ebc0f56034745546496c361be9403ea693f75040089403571a6ee36d298b46fd9de", + "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" + } + ] + }, + { + "seqno": 147, + "wire": "880f0d023433d9de4085aec1cd48ff86a8eb10649cbf6496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bffa", + "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" + } + ] + }, + { + "seqno": 148, + "wire": "88d5c9f8efd4e50f0d84682171bfc8dc6c96c361be940094d27eea0801128015c6c5719694c5a37f6496dc34fd280654d27eea080112816ae321b8dbea62d1bfe3", + "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" + } + ] + }, + { + "seqno": 149, + "wire": "885f961d75d0620d263d4c7441eafb50938ec415305a99567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb0f0d023335e0e5", + "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" + } + ] + }, + { + "seqno": 150, + "wire": "488264025885aec3771a4b5f92497ca589d34d1f6a1271d882a60b532acf7f0f1fbe9d29aee30c52b8e4abca1721e962944a921cfd4c59c7549416cff13007e09068e192faacc8cbf782f34cddbeedebae3afe0038265e032e5f6af5d71d05df768dd06258741e54ad9326e61d5dbfdcedf6e40f0d023133", + "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" + } + ] + }, + { + "seqno": 151, + "wire": "88e8c8e7e6e50f28bd41508803f6a5634cf031f6a17cd66b0a88375b57d280696d27eeb0801128166e09fb8d32a62d1bfed490f48cd540b8e4abca1721e9fb531a535eaaa8f55f87352398ac4c697fe50f0d023433", + "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" + } + ] + }, + { + "seqno": 152, + "wire": "88ded2bff8ddee0f0d8374407355830bce87e66c96df697e94640a6a225410022502fdc106e080a62d1bff6496dc34fd280654d27eea080112816ae34e5c0b2a62d1bfed", + "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" + } + ] + }, + { + "seqno": 153, + "wire": "88e1d5c2fbe0f10f0d8313ccb355836990bfe96c96e4593e94642a6a2254100225001b8215c65d53168dff6496dc34fd280654d27eea0801128166e36edc0baa62d1bff0", + "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" + } + ] + }, + { + "seqno": 154, + "wire": "88e4d8c5fee3f40f0d83682d07c3eb6c96df3dbf4a002a693f75040089403f702d5c0b8a62d1bf6496dc34fd280654d27eea080112816ae34edc134a62d1bff2", + "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" + } + ] + }, + { + "seqno": 155, + "wire": "88588eaed8e8313e94a47e561cc581c003c9e06496dc34fd280654d27eea0801128166e32fdc69953168dfdfc97f3b8ddda43f3f3f3f3f3f3f3f2d89ff7f3b8f08586581002251cb827ee34ca90e8f4089f2b585aa42d893525f8702e00baa20a447fbf20f0d8371d7c1f7", + "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" + } + ] + }, + { + "seqno": 156, + "wire": "88ebdfcc54012aebfc0f0d83744e355583699107f46c96c361be940094d27eea0801128015c69bb8cb2a62d1bf6496dc34fd280654d27eea0801128166e34edc684a62d1bffb", + "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" + } + ] + }, + { + "seqno": 157, + "wire": "885891aed8e8313e94a47e561cc581d75d7000075f87352398ac5754dfead27f078ddda43f3f3f3f3f3f3f3f2db22f7f078f085813020044a3d702d5c0b2a43a3f4089f2b567f05b0b22d1fa868776b5f4e0df0f0d83640f335584109d08036196dc34fd280654d27eea0801128166e09fb8d34a62d1bf6c96e4593e94642a6a2254100225042b826ae34ca98b46ff6496df697e9413ea651d4a080165410ae09ab8d32a62d1bf7f2e88ea52d6b0e83772fffa", + "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" + } + ] + }, + { + "seqno": 158, + "wire": "885891aed8e8313e94a47e561cc581d75d6df79fff00f3dbc6c5c40f0d033633315585109d0b4d7fc36c96e4593e94642a6a2254100225042b8266e36053168dff6496df697e9413ea651d4a080165410ae099b8d3ea62d1bfc2fe", + "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" + } + ] + }, + { + "seqno": 159, + "wire": "88fdf1decffcc70f0d836d971c5583105c7fc66c96df3dbf4a002a693f75040089413371a72e01b53168df6496dc34fd280654d27eea080112816ae099b8cb6a62d1bfc5", + "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" + } + ] + }, + { + "seqno": 160, + "wire": "885891aed8e8313e94a47e561cc581d75d6df7835f9c1d75d0620d263d4c795ba0fb8d04b0d5a7ed424e3b1054c16a6559effbe3408cf2b0d15d454addcb620c7abf8769702ec8190bffcd0f0d836c226fc6cb6c96e4593e94642a6a2254100225042b8266e34153168dff6496df697e9413ea651d4a080165410ae099b8d054c5a37fca", + "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" + } + ] + }, + { + "seqno": 161, + "wire": "885885aed8e8313ffae7d87f028712e05db03a277fd10f0d8465e6da6bfacf6c96c361be940094d27eea0801128015c69cb81794c5a37f6496dc34fd280654d27eea080112816ae322b800298b46ffce", + "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" + } + ] + }, + { + "seqno": 162, + "wire": "885891aed8e8313e94a47e561cc581d75d6df705c65a839bd9abecc6d50f0d8471e69a775585109d03ce7fd46c96e4593e94642a6a2254100225042b826ae082a62d1bff6496df697e9413ea651d4a080165410ae09ab820298b46ffd3", + "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" + } + ] + }, + { + "seqno": 163, + "wire": "885886a8eb10649cbff1c264022d317b8b84842d695b05443c86aa6ff27f1e8ddda43f3f3f3f3f3f3f3f2d89bf7f1e8f08586581002251cb827ee34d290e8f7f278702e0032a20a447de6196dc34fd280654d27eea0801128166e09fb8d32a62d1bf0f0d8308997bda4085aec1cd48ff86a8eb10649cbf", + "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" + } + ] + }, + { + "seqno": 164, + "wire": "88c5bef8c9c4c3f77f038ddda43f3f3f3f3f3f3f3f2d81ffc20f28b5f66ae025c27bfb5243d233550528a9721e9fb50be6b3585441b869fa50205b49fbac20044a05ab827ee34d298b46ffb52b1a67818f7f028702e071d5105223e2e00f0d03313338dd", + "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" + } + ] + }, + { + "seqno": 165, + "wire": "88588da8eb10649cbf4a54759093d85fc1fbccc7c6768dd06258741e54ad9326e61e5c1f408ef2b0d15d454d3dc8b772d8831eaf03342e30408bf2b5a35887a6b1a4d1d05f8cc9820c124c5fb24f61e92c01ff02408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934fd8e74090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb6196dc34fd280654d27eea0801128166e09fb8d38a62d1bf0f0d84136e320f6c96e4593e94642a6a225410022504cdc0b971b714c5a37f52848fd24a8f0f138ffe5f6c2eb619051c91ba4903701fcf", + "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\"" + } + ] + }, + { + "seqno": 166, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bfca5f87352398ac4c697f6c96df3dbf4a080a6a2254100215020b8276e36f298b46ffc10f138efe40d4631965089e94840dc07f3f768dd06258741e54ad9326e61d5dbfef4003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7f6196dc34fd280654d27eea0801128166e09fb8d3aa62d1bf0f0d023432", + "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" + } + ] + }, + { + "seqno": 167, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fd0c3d66c96d07abe940bca65b68504008540bf700cdc65d53168dfc60f138ffe4627d913ae38ec8d364206e03f9fc24001738be393068dda78e800020007c10f0d023432", + "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" + } + ] + }, + { + "seqno": 168, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b0342136f39f5f88352398ac74acb37f768abda83a35ebddbef42073e8f7c57f028abda83a35ebddbef420730f0d033831385585644169e7bfc66497dd6d5f4a01a5349fba820044a05db8cb571a6d4c5a37fff5", + "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" + } + ] + }, + { + "seqno": 169, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffd00f138efe401232dc6414a3649206e03f9fcc54012acccb0f0d03393534dc408a224a7aaa4ad416a9933f830befb96496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd6103a265a6995b784006db038fb2b5e13e0000000000003c27040ea", + "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" + } + ] + }, + { + "seqno": 170, + "wire": "88cddfd2e5ccd40f138ffe4627d913ae38ec8d364206e03f9fd07f088be393068dda78e800020037cf0f0d023432", + "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" + } + ] + }, + { + "seqno": 171, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692ffe16496dc34fd2816d4d27eea08007940b97000b800298b46ff7f13e6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f408cf2b794216aec3a4a4498f57f01300f28fe1d5d20cd2db03d2e271e56f79b3cff6047ff3fe951678bfd7957760e2c4f565d73b58767188b9ba7f8fc3a30b5738ff6d4fcd8785b3a70ff4b6df01da3fff2dc9ff9ff7c7f7ed4ac699e063ed42f9acd6151061b0df4a002b612c6b08016540b3704fdc69d53168dff6a487a466aa05c7255e50b90f4fda98d29af55547a5f92497ca589d34d1f6a1271d882a60b532acf7fd40f0d830b4e33", + "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" + } + ] + }, + { + "seqno": 172, + "wire": "88ec408aa924396a4ad416a9933f023432d9648872e09fb8d0948747d840874d8327535531a49a66391c7a3908b04af85668202ad1c8f8961bcdbe1648079f0b5f4089f2b567f05b0b22d1fa868776b5f4e0dfd8f40f0d023534", + "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" + } + ] + }, + { + "seqno": 173, + "wire": "890f0d0130d8408721eaa8a4498f5788ea52d6b0e83772ffea6496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfdf", + "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" + } + ] + }, + { + "seqno": 174, + "wire": "885f961d75d0620d263d4c7441eafb50938ec415305a99567be50f0d023335dcc1", + "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" + } + ] + }, + { + "seqno": 175, + "wire": "88768c86b19272ad78fe8e92b015c37f0ac6acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a5fc1c46a6f8720d4d7ba11a9af75f1a9938c2353271be353570daa64d37d4e1a7229a61e3fcff588ba6d4256b0bdc741a41a4bf6496d07abe94036a693f7504008940b3704fdc69e53168df0f28ff1c949059da3c0ceb3db5b5aa5eef62f37f062c7941bc54eb2a5ced82c9fde58ff043fc061e3cdeb732de4c9e78cbdf469cdc5bedb75efd98f1eac365fbb83ce7f592cfd5ba67db7e2b19f04589b1dc3b7355937e6e7ef533ef9f16c524f99a93760b34beb60267d50a7b03ed4be7a466aa05d36d952e43d3f6a60f359ac2a20df3dbf4a004b681fa58400b2a059b827ee34f298b46ffb5358d33c0c75f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e798624f6d5d4b27f5a839bd9abf9e3", + "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" + } + ] + }, + { + "seqno": 176, + "wire": "88c4c3f45f91497ca589d34d1f649c7620a98386fc2b3dbf58a0aec3771a4bf4a547588324e5fa52a3ac849ec2fd294da84ad617b8e83483497f6196dc34fd280654d27eea0801128166e09fb8d3ca62d1bf0f0d83682d0bcb7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 177, + "wire": "887f0d842507417f58b5aec3771a4bf4a523f2b0e62c00fa52a3ac419272fd2951d6424f617e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692f6495dc34fd2815328ea50400014006e003700053168dff6c95dc34fd2815328ea50400014006e003700053168dff4085aec1cd48ff86a8eb10649cbf768986434beb716cee5b3ff10f0d0234350f28dd4401fa17cb607db091a27cb3b1aa0d8fce8f18be6cfdf45097c5fe75d5d64efbb2f5f65713ab4738bc4107cfda958d33c0c7da85f359ac2a20d07abe94032b693f758400b4a059b827ee34f298b46ffb5243d2335500e5f410af5153f77f0ed9acf4189eac2cb07f33a535dc6181c8b8e5f410af5152c5761bb8c9e97f34d1fcfd297b5c1fca9a756452feed6a69c97d486fe81a97f0711a9af7423535eebe353570daa6adfb46a64d37d4bdab429a61e2a6edf0a9ab7defe7", + "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\"" + } + ] + }, + { + "seqno": 178, + "wire": "48826402ddc1dcdbda0f28bd41508803f6a5634cf031f6a17cd66b0a88375b57d280696d27eeb0801128166e09fb8d3ea62d1bfed490f48cd540b8e4abca1721e9fb531a535eaaa8f50f1fb29d29aee30c58ba6db2a5c87a58b188e4ff24909007e2b349036d7c13b96c803f169a481975b6dc68416d979c65a7df7df17f6196dc34fd280654d27eea0801128166e09fb8d3ea62d1bf0f0d01305f96497ca589d34d1f6a1271d882a60c9bb52cf3cdbeb07f", + "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" + } + ] + }, + { + "seqno": 179, + "wire": "887689c540d08c2644ea77677f03c6acf4189eac2cb07f2c473b1e192315b35afe69a3f9fa52f6b83f9d3ab2297f76b52f6adaa69c97d4bdc368d4bf8388d4d7ba11a9ab86d52ef0dca5ed5a14d30f153269dffcff0f28deae38ac4c7117bc0259b65b69c0aec85f699036e32d81b081f0b6ebeb81702e165b0bed3ed85a71a77ed4be7a466aa05c87a925f29f058d721e9fb53079acd615106eb6afa500cada4fdd61002ca8166e321b8db4a62d1bfed4d634cf031f40872785905b3b96cf87a261ac3aeb7002589caec3771a4bf4a523f2b0e62c00fa52a3ac419272fd2951d6424f617f64022d315f95352398ac4c697ec938ec4153064dda9679e6df583f5b842d4b70ddd46196dc34fd280654d27eea0801128166e321b8db4a62d1bf", + "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" + } + ] + }, + { + "seqno": 180, + "wire": "c85892ace84ac49ca4eb003e94aec2ac49ca4eb0035d89ac7626a2d8bce9a68f5f87497ca589d34d1fca6496d07abe94138a65b68502fbeea806ee001700053168df6c96dc34fd280654d27eea0801128166e09fb8d3ea62d1bf0f1fa89d29aee30c124a9745674f924e3aa62ae43d2c52590c36133db4c6862b3792d0c566f25a1798d2ff7f0aabbdae0fe74eac8a5fddad4bdab6a9af7427535eebe753570daa64d37d4e1a72297b568534c3c5486fe81ff3d176ad86b19272b025c4b882a7f5c2a379fed4a4f2448450c09712e20a9aab2d5bb767600bbebbc55a535685ac9cb4370f28ff6cac7626a2d8b0202e9ad3ef40334dd61e1b35610f7e1de6f7eef61068cbe3ad78adc2cf2f58bf095ddcdabf73f3cf95515d545876e54e2f2eeac7e88ecbe78c9aaea383546ef2697f4d7b67a19b2bdde19ddc03cfa6ad38bf42d3a1b346a1e2ad9929efbcf4f0aedd4d9c9ca9ebe6ec2d766eacc8e5fb297f5cd79ff7ca3c19ec5e2484d34ecc9abc61bafef95515d94b18386b14b313bd1b70ecdf9756c85cb43e32ce0b1ad5b19ced2a2bacfe63708eeaeda1566ffda85f359ac2a20dd6d5f4a0195b40ec58400b2a059b827ee34fa98b46ffb52b1a67818fb5243d2335502e8ace9f249c754c55c87a7f4082492a8424e7310b7b86a8b31d261a4bdee7", + "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" + } + ] + }, + { + "seqno": 181, + "wire": "d10f1fca9d29aee30c58ba6db2a5c87a58b18252860d2300624908c058acd2301798b4d231fe4c73cd416298d2417a1c1bb064dfb594e7c14649bce9409be9ef8bda2407c4c73cd41622772d9007d0d4f3f85f92497ca589d34d1f6a1271d882a60e1bf0acf7768abc73f53154d0349272d90f0d8264007f308a0fda949e42c11d07275f", + "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" + } + ] + }, + { + "seqno": 182, + "wire": "88d3768586b19272ff589baed8e8313e94a47e561cc581907d295d87f3e96b0bdc741a41a4bfc8d97f0799bdae0fe6f70daa437f429ab86d534eadaa6edf0a9a725ffe7f0f28cc34048e42362906b46cc8d2cd4aebeb464740b3211064001c964947f6a17cd66b0a88341eafa500cada4fdd61002d28166e09fb8d3ea62d1bfed4ac699e063ed490f48cd540b9eb2d5e57a8a90f0d023433de5f87352398ac4c697f", + "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" + } + ] + }, + { + "seqno": 183, + "wire": "88d7769186b19272b025c4bb2a7f578b52756efeff7f3188d78f5b0daecaecff7f02afbdae0fe74eac8a5ee1b46a437f40d4bf8388d4df0e41a9ab86d52ef0dca64d37d4e1a72297b568534c3c54c9a77ff30f28cbaed4c410bcdc0c85f699036e32d81b081f0b6ebff6a17cd66b0a8839164fa50025b28ea58400b2a059b827ee34fa98b46ffb52b1a67818fb5243d2335502f65b19887aabb0fd0a44ae43d30f0d0234394088ea52d6b0e83772ff8f49a929ed4c0c83e94a47e607df03bf7f2488cc52d6b4341bb97fc3", + "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" + } + ] + }, + { + "seqno": 184, + "wire": "88dc769186b19272b025c4b884a7f5c23b6a4dbfdf7f0390d78f5b0daecae102c1b63b6a4dacaed7e258acaec3771a4bf4a523f2b0e62c00fa52a3ac419272fd2948fcac398b03ce34007d294da84ad617b8e83483497fc70f28dfa3a26c4c70172fab38f4cbc11464f5a6cd80d1bf9f8d3bf40b4ef843a73c20d37f933c731f0c381fef74932acdffb50be6b3585441badabe94032b693f758400b2a059b827ee34fa98b46ffb52b1a67818fb5243d2335502f41ba192b90f4f0f0d0234336496dd6d5f4a01a5349fba820044a059b827ee34fa98b46fe8c7", + "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" + } + ] + }, + { + "seqno": 185, + "wire": "88f3f258b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007fe5c80f0d023433eb", + "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" + } + ] + }, + { + "seqno": 186, + "wire": "88f4f3bee50f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71a7d4c5a37fda9ac699e063fc80f0d023433e1", + "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" + } + ] + }, + { + "seqno": 187, + "wire": "88f4f3bee50f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71a7d4c5a37fda9ac699e063fc80f0d023433e1", + "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" + } + ] + }, + { + "seqno": 188, + "wire": "88f4f3bee50f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71a7d4c5a37fda9ac699e063fc80f0d023433e1", + "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" + } + ] + }, + { + "seqno": 189, + "wire": "8876871c83ad3dd80ae0c9c40f28ff01b131df1a46083f9ea5f5026db2ab9dc745a58190bed3206dc65b036103e16dd7ee17cd66b0a885306e1a7fde93f7ff6107fb036ab3089f55985a7ffdebddbffd880115c644b5e3d358d268e82c09b2d2ff3f7ac699e063eef9e919aa8171c83ad74f7fbc1e6b3585441a0f57d280656d27eeb08016940b3704fdc69f53168dff0f0d023432", + "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" + } + ] + }, + { + "seqno": 190, + "wire": "88f552848fd24a8f0f1392e4c7f220bed3ab0596c2f01e64410001fcff6c96df3dbf4a002a693f75040089410ae05eb8d054c5a37f5f88352398ac74acb37f0f0d84105f69dfef7f0888ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 191, + "wire": "88e676b686b19272b025c4bb4a7f5c2a379fed4bf0f1604a5279224228604b897694d5596addbb3b005df5dd1a949e48a51a12498cc09769717f0f28c6d7c2eedc1be1db8b06f81e144169a71b6dd65e7fed490f48cd5415db1d234988b90f4fda85f359ac2a20df697e94032b693f758400b6a059b827ee34fa98b46ffb52b1a678180f0d01317f0ce2bdae0fe74eac8a5fddad4bdab6a99e1e4a5ee1b5486fe83a97f0713a9be1c87535ee84ea6bdd7cea64e309d4c9c6f9d4c79371d4d5bf59d4d5c36a9ba1d0752ef0dca70d3914bdab429a61e2a64d3bd4bf834297b4ef5376f854d7b70299f55efe7f5894a8eb2127b0bf4a547588324e5fa52bb0ddc692ffedf1dd", + "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" + } + ] + }, + { + "seqno": 192, + "wire": "88d36c97df3dbf4a09c5340fd2820042a05bb8dbf719714e1bef7f0f0d023433d1588aa47e561cc5802f0996dd6196dc34fd280654d27eea0801128166e09fb8d814c5a37fc4", + "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" + } + ] + }, + { + "seqno": 193, + "wire": "88d67f03b5acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5fddad4bdab6a97f0711a9be1c8353570daa5de1b94e1a727f3d46496dc34fd280654d27eea0801128166e09fb8d814c5a37f5895a47e561cc5801f4a547588324e5fa52a3ac849ec2ff3c10f0d023433c70f28b6bda2fdf83ee43d23355010681d05a4b2186b90f4fdd634cf031f65f359ac2a20dd6d5f4a01a5349fba820044a059b827ee36053168df", + "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" + } + ] + }, + { + "seqno": 194, + "wire": "88d97f01c7acf4189eac2cb07f33a535dc61848e65c72525a245c87a58f0c918ad9ad7f34d1fcfd297b5c1fcebdd09d4d7baf9d4d5c36a9ba1d0a6adfb54bbc37297f76b521cf9d4bdab6ff3f45886a8eb2127b0bfe40f0d023335d8c3c9", + "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" + } + ] + }, + { + "seqno": 195, + "wire": "885a839bd9ab5283a8f5175899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fdbc6e77f03cbacf4189eac2cb07f33a535dc61894d4150b8e48ec324ab90f4b1e192315b35afe69a3f9fabdae0fe74eac8a6bdd0a9af75f53570daa64d37d4e1a7229a61e2a5fc1a14ddbe15356fbdfcff7688fcd7831c6c05717f0f28e2b2314178db335de84068e9cdbd3e7a79f2989cefe301b07bd1e756fd9ef45fe02d1ef878d3bf078d5bf0074fbebb21d9f6a5634cf031f6a487a466aa05c7247619255c87a7ed42f9acd6151061b0df4a002b612c6b08016540b3704fdc6c0a62d1bf0f0d023539", + "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" + } + ] + }, + { + "seqno": 196, + "wire": "88c2c1c0ddc8e9bfbe0f28e3b2314178dc335df783ce8dfa1ad3ef67375e8e55ac7aee49f47bd1bfa8347b843a7a680e8bfc3ce8bfd7ce9de46f04383ed4ac699e063ed490f48cd540b8e48ec324ab90f4fda85f359ac2a20c361be940056c258d61002ca8166e09fb8d814c5a37ff0f0d023539", + "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" + } + ] + }, + { + "seqno": 197, + "wire": "88588da8eb10649cbf4a54759093d85f4085aec1cd48ff86a8eb10649cbf5f92497ca589d34d1f6a1271d882a60b532acf7fc5f37b8b84842d695b05443c86aa6f768dd06258741e54ad9326e61e5c1f408ef2b0d15d454d3dc8b772d8831eaf03342e30408bf2b5a35887a6b1a4d1d05f8cc9820c124c5fb24f61e92c014090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb408bf2b4b60e92ac7ad263d48f89dd0e8c1ab6e4c5934f408cf2b0d15d454addcb620c7abf8769702ec8190bff7f21868776b5f4e0dfc16196dc34fd280654d27eea0801128166e09fb8d854c5a37f0f0d84134c89ef6c96e4593e94642a6a225410022504cdc0b971b714c5a37fde0f138ffe5f6c2eb619051c91ba4903701fcf", + "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\"" + } + ] + }, + { + "seqno": 198, + "wire": "88588ca47e561cc58190b6cb80003f5f86497ca582211fd1e00f138dfe5e03e40bcf371889206e03f9c9c8c2c50f0d8375d1335585742eb2e35f6196dc34fd280654d27eea0801128166e09fb8d894c5a37f6c96e4593e94134a6a225410022502e5c65bb807d4c5a37f6496dc34fd282714d444a820059500e5c0b371a794c5a37fe1", + "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" + } + ] + }, + { + "seqno": 199, + "wire": "88c35f901d75d0620d263d4c741f71a0961ab4ffd6e50f138efe40f32d32cb4e4622481b80fe7fcecdc7ca0f0d84085a7dbf5585742eb2e33fc26c96e4593e94134a6a225410022502e5c65fb8dbca62d1bf6496dc34fd282714d444a820059500e5c0b371a7d4c5a37fe5", + "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" + } + ] + }, + { + "seqno": 200, + "wire": "88d7d3f464022d316c96d07abe940bca65b68504008540bf700cdc65d53168dfea0f138ffe4627d913ae38ec8d364206e03f9f768dd06258741e54ad9326e61d5dbf4001738be393068dda78e800020033cd0f0d023432", + "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" + } + ] + }, + { + "seqno": 201, + "wire": "88cb5f87352398ac5754dfdeed0f138dfe5a8e3215f0b91889206e03f9d6d5cfd20f0d84081f705fc5c96c96e4593e94134a6a225410022502e5c65eb8cb2a62d1bfc4eb", + "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" + } + ] + }, + { + "seqno": 202, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bfda5f87352398ac4c697f6c96df3dbf4a080a6a2254100215020b8276e36f298b46fff10f138efe40d4631965089e94840dc07f3fc4d37f20a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7fce0f0d023432", + "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" + } + ] + }, + { + "seqno": 203, + "wire": "88d1c3e3f20f138efe492b2592591d6e311240dc07f3dbdad4d70f0d831000d7cfce6c96e4593e94134a6a225410022502e5c65db821298b46ffcdf0", + "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" + } + ] + }, + { + "seqno": 204, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46fff60f138efe401232dc6414a3649206e03f9fc954012ac3d30f0d03393535e2408a224a7aaa4ad416a9933f831000f76496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd6103a265a6995b784006db038fb2b5e13e0000000000003c27040eb", + "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" + } + ] + }, + { + "seqno": 205, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b03207dc75eff9768abda83a35ebddbef42077dfdec87f0f8abda83a35ebddbef420770f0d84138cb8ff5584704c805fda6496df697e94038a693f750400894082e04571a794c5a37f408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 206, + "wire": "88efebced5d452848fd24a8f0f138ffe4627d913ae38ec8d364206e03f9fd47f038be393068dda78e800020035e30f0d023432", + "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" + } + ] + }, + { + "seqno": 207, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c81c10bf5f88352398ac74acb37f768abda83a35ebddbef4207be8e7d17f028abda83a35ebddbef4207b0f0d8469b65f6bc6e26496e4593e9403aa693f7504008940bf71a7ae32253168dfc5", + "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" + } + ] + }, + { + "seqno": 208, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692fff36496dc34fd2816d4d27eea08007940b97000b800298b46ff7f16e6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f408cf2b794216aec3a4a4498f57f01300f28ff101d5d20cd2db03d2e26ffdfff97bcd9e7fb023ff9ff4a8b3c5febcabbb071627ab37ff02d61d9c622e6e9fe3f0e8c2d5ce3fdb53f361e16ce9c3fd2db7c07afff9caf8bfebff260ff65b337f1fc7cd3fe6e83fda3bf6fb52b1a67818fb50be6b358544186c37d2800ad84b1ac20059502cdc13f71b1298b46ffb5243d2335502e392af285c87a7ed4c694d7aaaa3d7ff5e70f0d830b2f87", + "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" + } + ] + }, + { + "seqno": 209, + "wire": "88768c86b19272ad78fe8e92b015c37f01c6acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a5fc1c46a6f8720d4d7ba11a9af75f1a9938c2353271be353570daa64d37d4e1a7229a61e3fcff588ba6d4256b0bdc741a41a4bf6496d07abe94036a693f7504008940b3704fdc6c4a62d1bf0f28ff1b94906bf185bc5961b1fdf8f539807c7afaeae55438814d0f1d9a0b740ffa2d096f4a1a0f37adccb793279e32f7d1a73716fb6dd7bdc262f3beaba2cd97a7ac58bb7ef17f5bafbacf822c4d8ee1db9aac9bf373f7a99f7cf8b62927ccd49bb059a5f5b0133ea853d81f6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b1298b46ffb5358d33c0c7f5f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e798624f6d5d4b27f5a839bd9abfbee", + "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" + } + ] + }, + { + "seqno": 210, + "wire": "488264027f05afbdae0fe74eac8a5ee1b46a437f40d4bf8388d4df0e41a9ab86d52ef0dca64d37d4e1a72297b568534c3c54c9a77ff36496df3dbf4a002a651d4a05f740a0017000b800298b46ff0f28a0ae00ad26ba75eb6dbcad4a0ddf7ac699e063eef9e919aa817b2534f6c6b90f4f0f1fc79d29aee30c1a35c7255e50b90f4b15f9e9fe4669242d9005ef8416681975e7001f8191263d5020a9b4d223faff4e3a2744d85f6c4d3227df71a7ffd7d7faff5fdfdfc58590d6410f0d0130", + "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" + } + ] + }, + { + "seqno": 211, + "wire": "88cb4085aec1cd48ff86a8eb10649cbfcbcac90f28ff111d5d20cd2db03d2e276fe3bde6cf3fd811ffcffa5459e2ff5e55dd838b13d59bfbf2d61d9c622e6e9fe3f0e8c2d5ce3fdb53f361e16ce9c3fd2db7c07afff9caf8bfebff260ff65b3438ee6d7ecbfc7fa260fda6e9b6f3fb52b1a67818fb50be6b358544186c37d2800ad84b1ac20059502cdc13f71b1298b46ffb5243d2335502e392af285c87a7ed4c694d7aaaa3d70f0d023433e4f2", + "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" + } + ] + }, + { + "seqno": 212, + "wire": "890f0d0130f2d4be6496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfe6", + "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" + } + ] + }, + { + "seqno": 213, + "wire": "885f961d75d0620d263d4c7441eafb50938ec415305a99567b4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb0f0d023335f6d8", + "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" + } + ] + }, + { + "seqno": 214, + "wire": "88cccbc25f91497ca589d34d1f649c7620a98386fc2b3dc758a0aec3771a4bf4a547588324e5fa52a3ac849ec2fd294da84ad617b8e83483497ff80f0d83682d0bda7b8b84842d695b05443c86aa6f", + "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" + } + ] + }, + { + "seqno": 215, + "wire": "c8cfce58b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007fc60f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b654c5a37fda9ac699e063fec0f0d0234336196dc34fd280654d27eea0801128166e09fb8db2a62d1bf0f1fad9d29aee30c495d2bc85a642f95ea2a583468b9256692065d6fe24aedb4d240c85f699036e32d81b081f0b6ebffcc", + "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" + } + ] + }, + { + "seqno": 216, + "wire": "cad1d0bfc70f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b654c5a37fda9ac699e063fed0f0d023433be0f1fa99d29aee30c24732178e8b4bd4665c87a584192561a69f7ffc34903217da640db8cb606c207c2dbafffcc", + "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" + } + ] + }, + { + "seqno": 217, + "wire": "88d1d0bfc70f28c2b4d240cb6f09f7c2db6f32ebae38179d0fda97cf48cd540bd6b2645c87a7ed4c1e6b3585441be7b7e940096d03f4b08016540b3704fdc6d953168dff6a6b1a67818fed0f0d023433be", + "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" + } + ] + }, + { + "seqno": 218, + "wire": "886197dc34fd28a0195349fba820044a059b827ee36ca98b46ff7f1f842507417f7689861e458f716cee5b3f7f0db1acf4189eac2cb07f33a535dc618f1e3c2e3907277320f62f5152c78648c56cd6bf9a68fe7eaf6b83f9d3ab229a725ffe7f0f0d0232315f901d75d0620d263d4c741f71a0961ab4ff0f28d61c7000000aacc3bcba5dc606993fe77ca0c520323fb7d9bab5ebcd71f9dfdd9ddf6a5f3d2335502e3907277320f62f5153f6a60f359ac2a20dc34fd28a0195349fba820059502cdc13f71b654c5a37fda9ac699e063f", + "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=/" + } + ] + }, + { + "seqno": 219, + "wire": "cf7f00ccacf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a69c97d4bdc368d486fe81a97f0711a9af7423535eebe353570daa6e8740d4bbc3729af86d52f6ad0a69878a9934effe7f408290889aa06b48442ccac15cd524b6543a1790b4c85f2b90f4a815df5c220f28d190b4c85f3009a034f3cf3cf81a0b40136fb82001c105c6dc7c2275c642d3acb7f7ac699e063eef9e919aa81790b4c85f2bd454fde0f359ac2a20df3dbf4a0195b49fbac20084a099b8cbb719654c5a37ff6496df3dbf4a002a651d4a08007d4002e001700053168dff58bba8eb10649cbf551d6424f617ea9b5095ac2f71d0690692fd523f2b0e62c00faaec3f9f4b585ee3a0d20d25faa8eb26c1d4894f653f55d86ee3497fd00f1fbd9d29aee30c495d2bc85a642f95ea2a5890b490f54abf4ae6ff0a9b868d0aba490691dc92b349032eb7f12576da6920642fb4c81b7196c0d840f85b75ff0f0d01307691ca54a7d7f4eae25c4bf7100200880dff7f", + "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)" + } + ] + }, + { + "seqno": 220, + "wire": "88c27f029ba06b48442ce2ccae6a925b2a1d0bc85a642f95c87a540aefae117f0f28d192ba60134069e79e79f034168026df704003820b8db8f844eb8c85a7596fef58d33c0c7ddf3d2335502f2574af216990be57a8a9fbc1e6b3585441be7b7e94032b693f75840109413371976e32ca98b46fc1e4c0d240824251024f4b0f0d03333038c0", + "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)" + } + ] + }, + { + "seqno": 221, + "wire": "d6dddccbd30f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b654c5a37fda9ac699e063f0f1fd09d29aee30c20b3525a92b566f25a17355dcc92d2590c35c87a5841531563b13516c8ad349fe563b13516cc97e06802f842088886449bb9600fc563b13516ce192fc0c85f699036e32d81b081f0b6ebffd8ca", + "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" + } + ] + }, + { + "seqno": 222, + "wire": "d6dddccbd30f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b654c5a37fda9ac699e063f0f1fad9d29aee30c495d2bc85a642f95ea2a583468b9256692069d07c495db69a48190bed3206dc65b036103e16dd7ffd8ca", + "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" + } + ] + }, + { + "seqno": 223, + "wire": "88c47f009ba06b48442ce2cd2e6a925b2a1d0bc85a642f95c87a540aefae117f0f28d192ba60134069e79e79f034168026df704003820b8db8f844eb8c85a7596fef58d33c0c7ddf3d2335502f2574af216990be57a8a9fbc1e6b3585441be7b7e94032b693f75840109413371976e32ca98b46fc35f87352398ac4c697fc3d5c00f0d023432c2", + "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)" + } + ] + }, + { + "seqno": 224, + "wire": "d8cc0f28bc31e296c2f6b4b513d41f7ac699e063eef9e919aa80d577324b496430d721e9fbc1e6b3585441be7b7e940056ca3a960bee814002e001700153168dffd6d57f07e4acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe756fc8a5fddad4bdab6a90dfd07537c390ea6bdd09d4d7baf9d4bdab49d4d5c36a9ba1d075356fda75376fd6a70d3914d7c36a97b568534c3c54c9a77a97f0685376f854d7b70299f55efe7f5886a8eb10649cbf0f1fcb9d29aee30c1295e65e43db1d0525062755ea2a58acde4b47f931cf35058aa34901aaee649692c861fc4c73cd4162253f131cf35058a7a60fdc525447b9c7b62327cebd7a19ccf51a7c41070f0d0130cc7691ca54a7d7f4eaecae15fb8801081903bfdf", + "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)" + } + ] + }, + { + "seqno": 225, + "wire": "db0f1fc49d29aee30c4cb566f25a17355dcc92d2590c35c87a589a91a49396cff2639e6a0b14c6920bd0e0dd8327ebbeaea060137c2dcade0e17f2209613e2639e6a0b113b96c8036196dc34fd280654d27eea0801128166e09fb8db4a62d1bfd9f65892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a1271d882a60e1bf0acf7768abc73f53154d0349272d90f0d033239337f288a0fda949e42c11d07275f", + "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" + } + ] + }, + { + "seqno": 226, + "wire": "88c20f28bc31e296c2f6b4b513d41f7ac699e063eef9e919aa80d577324b496430d721e9fbc1e6b3585441be7b7e940056ca3a960bee814002e001700153168dffdeddc6c5c40f0d023433d2c3", + "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)" + } + ] + }, + { + "seqno": 227, + "wire": "88e7e6d5dd0f28c6b4d240cb61136d884fbccb61759089f73ed4be7a466aa05c76c862d4429bb2e43d3f6a60f359ac2a20df3dbf4a004b681fa58400b2a059b827ee36d298b46ffb5358d33c0c7fc60f0d023433d4", + "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" + } + ] + }, + { + "seqno": 228, + "wire": "88e7e6d5dd0f28c6b4d240cbc17c2e32d3eebe27d965d13acfda97cf48cd540b8ed90c5a8853765c87a7ed4c1e6b3585441be7b7e940096d03f4b08016540b3704fdc6da53168dff6a6b1a67818fc60f0d023433c2", + "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" + } + ] + }, + { + "seqno": 229, + "wire": "88c2769186b19272b025c4bb2a7f578b52756efeff7f07d8bdae0fe74eac8a5fddad4bdab6a97b86d521bfa0ea5fc1c4ea6bdd09d4d7baf9d4d5c36a9ba1d0752ef0dca70d3914d30f1fe7e94acf4189eac2cb07f33a535dc61848e642f1d1697a8ccb90f4b1e192315b35afe69a3f9fdf6496df3dbf4a002a5f29140befb4a05cb8005c0014c5a37f5895a47e561cc5801f4a547588324e5fa52a3ac849ec2f0f28b98fac8483c484fb50be6b3585441a0f57d280656be522c20044a059b827ee36d298b46ffb52b1a67818fb5243d2335502f1d1697a8ccb90f4ff40878faac82d9dcb67839591370f0d023632cb", + "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" + } + ] + }, + { + "seqno": 230, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c81c0bbff5f4408cf2b0d15d454addcb620c7abf8769702ec8190bff4089f2b567f05b0b22d1fa868776b5f4e0df7f05a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f4001738abda83a35ebddbef4207b0f0d8469f7dd6f5584704c81afcd6496e4593e9403aa693f7504008940bf71a7ae09d53168df7f1f88ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 231, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b0340109a7bf5f88352398ac74acb37f768abda83a35ebddbef42073c7c6c57f058abda83a35ebddbef420730f0d846da101cfc4d36496e4593e9403aa693f750400894086e36ddc65e53168dfc3", + "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" + } + ] + }, + { + "seqno": 232, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034069913ffc2768abda83a35ebddbef4207bcbcac9c80f0d8465a089ffc7d66496e4593e9403aa693f75040089408ae320b817d4c5a37fc6", + "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" + } + ] + }, + { + "seqno": 233, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c81c107fc5768abda83a35ebddbef42077cecdcc7f058abda83a35ebddbef420770f0d846401743f5584704c819fdb6496e4593e9403aa693f7504008940bf71a7ae32253168dfcb", + "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" + } + ] + }, + { + "seqno": 234, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b0342684f3bfcac5d2d1d0cf0f0d8464400bdfc0dd6496e4593e9403aa693f7504008940bd7002b8dbca62d1bfcd", + "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" + } + ] + }, + { + "seqno": 235, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034275a137fccc4d4d3d2c30f0d84134179bfc2df6496e4593e9403aa693f7504008940bd71b6ee05c53168dfcf", + "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" + } + ] + }, + { + "seqno": 236, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b009d105d6bfcec9d6d5d4d30f0d846597da67c4e16496d07abe94036a693f75040089413371a76e34da98b46fd1", + "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" + } + ] + }, + { + "seqno": 237, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b03226de743fd0cfd8d7d6ce0f0d846c4cb6cfd4e36496df697e94038a693f7504008940b571a15c682a62d1bfd3", + "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" + } + ] + }, + { + "seqno": 238, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c802dbdfd2cddad9d8d70f0d8413eeb2e7d6e56496e4593e9403aa693f7504008940bf71a05c69e53168dfd5", + "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" + } + ] + }, + { + "seqno": 239, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c81f135fd4cfdcdbdad90f0d840b8d36ffd8e76496e4593e9403aa693f7504008940bf71b66e32d298b46fd7", + "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" + } + ] + }, + { + "seqno": 240, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b032f880267fd6d1dedddcdb0f0d840b8f3cf7cce96496e4593e9403aa693f75040089403f700ddc0b4a62d1bfd9", + "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" + } + ] + }, + { + "seqno": 241, + "wire": "88d0d7cfdfdeddce0f0d8465f0b2d7cdeaccd9", + "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" + } + ] + }, + { + "seqno": 242, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c81c0b9fd8d0e0dfdecf0f0d840bce38cfceebdbda", + "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" + } + ] + }, + { + "seqno": 243, + "wire": "88bed8768abda83a35ebddbef4206fe1e0df7f118abda83a35ebddbef4206f0f0d84109b69bfd0eddddc", + "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" + } + ] + }, + { + "seqno": 244, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b03207dc781fdbc0e3e2e1bf0f0d8469e75a73d1ee6496df697e94038a693f750400894082e04571b0a98b46ffde", + "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" + } + ] + }, + { + "seqno": 245, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b032075a6d9fddd8e5e4e3e20f0d84644e36e7d3f06496df697e94038a693f75040089403f7196ee34d298b46fe0", + "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" + } + ] + }, + { + "seqno": 246, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f00bfdfdae7e6e5e40f0d8369a75955840b8eb4f7f36496df3dbf4a01e5349fba820044a01eb8d3f700f298b46fe3", + "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" + } + ] + }, + { + "seqno": 247, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b03427da7c5fe2e1eae9e8e00f0d836c4cbf5584109d6c1f6196dc34fd280654d27eea0801128166e09fb8db4a62d1bf6496df3dbf4a01e5349fba820044a01cb827ae36e298b46fe7", + "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" + } + ] + }, + { + "seqno": 248, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034271f741fe6e1eeedeceb0f0d8369d79a5584109d6c3fc16497df3dbf4a01e5349fba820044a01bb8d3971b654c5a37ffea", + "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" + } + ] + }, + { + "seqno": 249, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85f69afe9cef1f0efcd0f0d8365e69955846c0d3edfc46496e4593e9403aa693f750400894133704edc132a62d1bfed", + "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" + } + ] + }, + { + "seqno": 250, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c842d33fecd1f4f3f2d00f0d83680dbd55846c0db41fc76496e4593e9403aa693f750400894133702cdc0b8a62d1bff0", + "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" + } + ] + }, + { + "seqno": 251, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c85d703fefe7408cf2b0d15d454addcb620c7abf8769702ec8190bff4089f2b567f05b0b22d1fa868776b5f4e0df4003703370a9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3fe90f0d83644f87558479a740cfcd6496e4593e9403aa693f7504008940b371b6ae044a62d1bf408721eaa8a4498f5788ea52d6b0e83772ff", + "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" + } + ] + }, + { + "seqno": 252, + "wire": "88eef5dac3c2c1d90f0d8465a69b7f5584704c805fd06496e4593e9403aa693f7504008940bf71a7ae32ca98b46fc0", + "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" + } + ] + }, + { + "seqno": 253, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bf4085aec1cd48ff86a8eb10649cbf5f87352398ac4c697f6c96df3dbf4a080a6a2254100215020b8276e36f298b46ff52848fd24a8f0f138efe40d4631965089e94840dc07f3f768dd06258741e54ad9326e61d5dbfcac90f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7f6196dc34fd280654d27eea0801128166e09fb8db6a62d1bf0f0d023432", + "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" + } + ] + }, + { + "seqno": 254, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffc30f138efe401232dc6414a3649206e03f9fc254012acec20f0d03393534c7408a224a7aaa4ad416a9933f830befb96496c361be940054ca3a940bef814002e001700053168dff4086f2b58390d27f9bd6103a265a6995b784006db038fb2b5e13e0000000000003c270405a839bd9ab", + "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" + } + ] + }, + { + "seqno": 255, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fcccb64022d316c96d07abe940bca65b68504008540bf700cdc65d53168dfcb0f138ffe4627d913ae38ec8d364206e03f9fca7f2e8be393068dda78e800020039ca0f0d023432", + "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" + } + ] + }, + { + "seqno": 256, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692ffd06496dc34fd2816d4d27eea08007940b97000b800298b46ff7f19e6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f408cf2b794216aec3a4a4498f57f01300f28ff191d5d20cd2db03d2e26b77ff09dfa58c7f80d7fd7cc36dd5adf9f998373f3261bdfff701bfd310ecf1879eafff3bcf8f6b3bb76476e0108fc0f51ff08ffd7f9ef9a3e5877ff9bc3abffed1ffe1f670afb68f38f3f5ff5d7affedd63fef26dedf6a5634cf031f6a17cd66b0a8830d86fa50015b096358400b2a059b827ee36e298b46ffb5243d2335502e392af285c87a7ed4c694d7aaaa3d75f92497ca589d34d1f6a1271d882a60b532acf7f6196dc34fd280654d27eea0801128166e09fb8db8a62d1bf0f0d830b4d3b", + "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" + } + ] + }, + { + "seqno": 257, + "wire": "88768c86b19272ad78fe8e92b015c37f03c6acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a5fc1c46a6f8720d4d7ba11a9af75f1a9938c2353271be353570daa64d37d4e1a7229a61e3fcff588ba6d4256b0bdc741a41a4bf6496d07abe94036a693f7504008940b3704fdc6dc53168df0f28ff1a94900a5a381463bfb8687bceac80c9e3f3bee6efd767e0f3bdbdec8639dfd7eb0ea665dbcdeb732de4c9e78cbdf469cdc5bedb75ef647601dcdc01e9c3456ecf7b7c7ef1cb76c67c11626c770edcd564df9b9fbd4cfbe7c5b1493e66a4dd82cd2fad8099f5429ec0fb52f9e919aa8174db654b90f4fda983cd66b0a8837cf6fd28012da07e961002ca8166e09fb8db8a62d1bfed4d634cf0315f95497ca58e83ee3412c3569fb24e3b1054c1c37e159e798624f6d5d4b27fce7b8b84842d695b05443c86aa6fd7", + "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" + } + ] + }, + { + "seqno": 258, + "wire": "88cedcdbcdccd90f138ffe4627d913ae38ec8d364206e03f9fd87f0c8be393068dda78e800020037d80f0d023432", + "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" + } + ] + }, + { + "seqno": 259, + "wire": "88cfdddccecdda0f138ffe4627d913ae38ec8d364206e03f9fd97e8be393068dda78e80002000bd90f0d023432", + "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" + } + ] + }, + { + "seqno": 260, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b032cba1137f5f88352398ac74acb37f768abda83a35ebddbef4207beae9e87f028abda83a35ebddbef4207b0f0d8469d680ff5584704c819ff86496df697e94038a693f7504008940bb71b05c0b8a62d1bfe8", + "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" + } + ] + }, + { + "seqno": 261, + "wire": "890f0d0130dfe8e46496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfe5", + "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" + } + ] + }, + { + "seqno": 262, + "wire": "88cecde65f91497ca589d34d1f649c7620a98386fc2b3dda58a0aec3771a4bf4a547588324e5fa52a3ac849ec2fd294da84ad617b8e83483497fd10f0d83682d0becca", + "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" + } + ] + }, + { + "seqno": 263, + "wire": "8858aaaed8e8313e94a6d4256b0bdc741a41a4bf4a5761fcfa5ac2f71d0690692fd2948fcac398b034c802dbdfc7768abda83a35ebddbef4206ff3f2f17f078abda83a35ebddbef4206f0f0d84680d38d7c66196dc34fd280654d27eea0801128166e09fb8db4a62d1bf6496e4593e9403aa693f7504008940bf71a05c69f53168dff1", + "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" + } + ] + }, + { + "seqno": 264, + "wire": "885886a8eb10649cbfeeeddf768dd06258741e54ad9326e61d5c1f7f17a7bdae0fe74ead2a5fddad4bdab6a97b86d1a9af742a6bdd7d4d5c36a97786e534c3c54ddbe1fe7ff9eb0f0d023433d2", + "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" + } + ] + }, + { + "seqno": 265, + "wire": "88f1f0efeeed0f138efe40d4631965089e94840dc07f3fecf8f70f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7fd90f0d023432", + "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" + } + ] + }, + { + "seqno": 266, + "wire": "88eae9e8ed0f138efe401232dc6414a3649206e03f9fece7f76196dc34fd280654d27eea0801128166e09fb8dbaa62d1bf0f0d83085c17f17f2883138f37e77f279bd61038e042cb4b6f0800db6f32fb6b5e7400000000000008401003e6", + "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" + } + ] + }, + { + "seqno": 267, + "wire": "88e5f3f2e4e3f00f138ffe4627d913ae38ec8d364206e03f9fefd4c00f0d023432", + "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" + } + ] + }, + { + "seqno": 268, + "wire": "88e5f3f2e4e3f00f138ffe4627d913ae38ec8d364206e03f9fef7f078be393068dda78e800020035dd0f0d023432", + "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" + } + ] + }, + { + "seqno": 269, + "wire": "88e6f4f3e5e4f10f138ffe4627d913ae38ec8d364206e03f9ff0d5c10f0d023432", + "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" + } + ] + }, + { + "seqno": 270, + "wire": "880f0d83132d39c10f1f9f9d29aee30c200b8a992a5ea2a58ee62f81c8c32e342640db01583e42bcc697c4f47689bf7b3e65a193777b3f5f87497ca589d34d1fe9", + "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" + } + ] + }, + { + "seqno": 271, + "wire": "885f8b497ca58e83ee3412c3569f6c96df697e9403ca681fa50400894102e01fb80754c5a37f6196c361be940094d27eea080112816ae320b807d4c5a37f6496dc34fd280654d27eea080112816ae320b807d4c5a37f4090f2b10f524b52564faacab1eb498f523f85a8e8a8d2cb768344b2970f0d8264417f288a0fda949e42c11d07275f5584784ebcf75890aed8e8313e94a47e561cc581e71a003fe1f2", + "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" + } + ] + }, + { + "seqno": 272, + "wire": "885f87352398ac4c697f6c96df3dbf4a09a5340fd2820044a0817022b8db8a62d1bf6196c361be940094d27eea0801128205c6c3700053168dff6496dc34fd280654d27eea0801128205c6c3700053168dffc6c50f0d840b8cbeffc455846df7d97bc3e6f7", + "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" + } + ] + }, + { + "seqno": 273, + "wire": "890f0d0130d1408721eaa8a4498f5788ea52d6b0e83772ff4085aec1cd48ff86a8eb10649cbfdfdec4", + "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" + } + ] + }, + { + "seqno": 274, + "wire": "8858a1aec3771a4bf4a547588324e5fa52bb0fe7d2d617b8e83483497e94a8eb2127b0bfbfc56c96df3dbf4a080a6a2254100215020b8276e36f298b46ff52848fd24a8f0f138efe40d4631965089e94840dc07f3f768dd06258741e54ad9326e61d5dbf4089f2b567f05b0b22d1fa868776b5f4e0df7f1aa9bdae0fe6ef0dca5ee1b54bdab49d4c3934a9938df3a9ab4e753570daa6bc7cd4dd0e83a9bf0673ff3f0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7f6196dc34fd280654d27eea0801128166e09fb8dbca62d1bf0f0d023432", + "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" + } + ] + }, + { + "seqno": 275, + "wire": "885892a8eb10649cbf4a536a12b585ee3a0d20d25f5f92497ca589d34d1f6a5e9c7620a982d4cab3df6c96c361be94036a6a225410022502fdc13f704f298b46ffc50f138efe401232dc6414a3649206e03f9fc454012ac36196dc34fd280654d27eea0801128166e09fb8dbea62d1bf0f0d03393533ca7f1f830befb96496c361be940054ca3a940bef814002e001700053168dff7f209bd6103a265a6995b784006db038fb2b5e13e0000000000003c270405a839bd9ab", + "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" + } + ] + }, + { + "seqno": 276, + "wire": "885899a8eb10649cbf4a54759093d85fa529b5095ac2f71d0690692fcfd564022d316c96d07abe940bca65b68504008540bf700cdc65d53168dfce0f138ffe4627d913ae38ec8d364206e03f9fcd7f248be393068dda78e800020039cb0f0d023432", + "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" + } + ] + }, + { + "seqno": 277, + "wire": "885894a8eb2127b0bf4a547588324e5fa52bb0ddc692ffd36496dc34fd2816d4d27eea08007940b97000b800298b46ff7f0fe6acf4189eac2cb07f33a535dc61824952e392af285c87a58f0c918acf4189e98ad9ad7f34d1fcfd297b5c1fce9d5914bfbb5a97b56d521bfa14d7ba13a9af75f3a9ab86d3a9ba1d0753869da75356fda752ef0dca5ed5a14d30f152fe0d0a6edf0a9af6e0fe7f7f1f01300f28ff1a1d5d20cd2db03d2e217ffcb09dfa58c7f80d7fd7cc36dd5adf9f998373f325d8b3e037fa621d9e30f3d5ffe779f1ed6776ec8edc0211f8193a9e1d44ffdffafff3f8fcb550ecf9fff9be1d20c18afeeffbdb56af2f4deae3a9a797b07261ef5f6a5634cf031f6a17cd66b0a8830d86fa50015b096358400b2a059b827ee36fa98b46ffb5243d2335502e392af285c87a7ed4c694d7aaaa3d7f5f92497ca589d34d1f6a1271d882a60b532acf7fcb0f0d03353339", + "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=8fG2RnOx8gy: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" + } + ] + }, + { + "seqno": 278, + "wire": "88c6d7ddc5c4d40f138ffe4627d913ae38ec8d364206e03f9fd37f048be393068dda78e800020037d10f0d023432", + "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" + } + ] + }, + { + "seqno": 279, + "wire": "88c7d8dec6c5d50f138ffe4627d913ae38ec8d364206e03f9fd47e8be393068dda78e800020033cd0f0d023432", + "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" + } + ] + }, + { + "seqno": 280, + "wire": "885886a8eb2127b0bfeaca6401307b8b84842d695b05443c86aa6f4086f2b5281c86938e640003cfb4d01713efbecb4f34f7d67f1f842507417f0f0d03353038", + "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" + } + ] + }, + { + "seqno": 281, + "wire": "88768c86b19272ad78fe8e92b015c37f09c6acf4189eac2cb07f2c78648c56cd6bf9a68fe7e94bdae0fe74eac8a5ee1b46a5fc1c46a6f8720d4d7ba11a9af75f1a9938c2353271be353570daa64d37d4e1a7229a61e3fcff58b1a47e561cc5801f4a547588324e5fa52a3ac849ec2fd295d86ee3497e94a6d4256b0bdc741a41a4bf4a216a47e47316007fe10f28c2b4d240c85f699036e32d81b081f0b6ebff6a5f3d2335502e9b6ca9721e9fb53079acd615106f9edfa50025b40fd2c20059502cdc13f71b7d4c5a37fda9ac699e063fe70f0d023433da", + "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" + } + ] + }, + { + "seqno": 282, + "wire": "890f0d0130d5e2e16496d07abe940054ca3a940bef814002e001700053168dff58b0aec3771a4bf4a547588324e5fa52a3ac419272c1b8a95af1cfd4c5fa52a3ac849ec2fd295d87f3e96b0bdc741a41a4bfe9", + "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" + } + ] + }, + { + "seqno": 283, + "wire": "88e2e3e9e1e00f138efe40d4631965089e94840dc07f3fdfdedd0f28b9874ead37b1e6801f6a487a466aa022f4a2a5c87a7ed42f9acd615106fb4bf4a01c5b49fbac20044a059b827ee32053168dff6a5634cf031f7f6196dc34fd280654d27eea0801128166e320b800298b46ff0f0d023432", + "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" + } + ] + }, + { + "seqno": 284, + "wire": "88dcdbdae10f138efe401232dc6414a3649206e03f9fe0d9ded80f0d03393534e47f18831000f7d7d6d5", + "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" + } + ] + }, + { + "seqno": 285, + "wire": "88d4e5ebd3d2e20f138ffe4627d913ae38ec8d364206e03f9fe1cbd90f0d023432", + "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" + } + ] + }, + { + "seqno": 286, + "wire": "88d4e5ebd3d2e20f138ffe4627d913ae38ec8d364206e03f9fe1f7d90f0d023432", + "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" + } + ] + }, + { + "seqno": 287, + "wire": "88d4e5ebd3d2e20f138ffe4627d913ae38ec8d364206e03f9fe17f0b8be393068dda78e800020007c00f0d023432", + "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" + } + ] + }, + { + "seqno": 288, + "wire": "88d1e6d0cfce0f28ff231d5d20cd2db03d2e273ae2277e9631fe035ff5f30db756b7e7e660dcfcc97fbb980dfe9887678c3cf57ff9de7c7b59ddbb23b700847e064a0191887ff500ac4ffdffbfeeb6bfc6ffc9725bfff35fef5475b9e7fbc9aac63e747ffda7fb47b1fff9f3303981ed9c66c7f6a5634cf031f6a17cd66b0a8830d86fa50015b096358400b2a059b8c82e000a62d1bfed490f48cd540b8e4abca1721e9fb531a535eaaa8f5fcdc00f0d03353336", + "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+)p4?5?fIu+)p4?5?fIu+)p4?5?fIu= 0) { + out.write(bytes, 0, copyBuffer.position()); + copyBuffer.clear(); + } + } + } + + @Override + public void writeTo(WritableByteChannel dst) throws IOException { + try (ReadableByteChannel src = asChannel()) { + copy(src, dst); + } + } + + @Override + public void discard() throws IOException { + if (consumed || closed) { + return; + } + + consumed = true; + closed = true; + try (var src = channel) { + drain(src, contentLength, copyBuffer()); + } + } + + @Override + public long contentLength() { + return contentLength; + } + + @Override + public String contentType() { + return contentType; + } + + @Override + public boolean isReplayable() { + return false; + } + + @Override + public boolean isAvailable() { + return !consumed; + } + + @Override + public void close() { + if (!closed) { + closed = true; + try { + channel.close(); + } catch (IOException e) { + throw new UncheckedIOException("Failed to close data stream", e); + } + } + } + + private void markConsumed() { + if (consumed) { + throw new IllegalStateException("DataStream is not replayable and has already been consumed"); + } + consumed = true; + } + + private ByteBuffer copyBuffer() { + if (buffer == null) { + buffer = ByteBuffer.allocate(BUFFER_SIZE); + } else { + buffer.clear(); + } + return buffer; + } + + private void copy(ReadableByteChannel src, WritableByteChannel dst) throws IOException { + if (src instanceof FileChannel fileChannel) { + long position = fileChannel.position(); + long size = fileChannel.size(); + while (position < size) { + long transferred = fileChannel.transferTo(position, size - position, dst); + if (transferred <= 0) { + fileChannel.position(position); + copyBuffered(fileChannel, dst, copyBuffer()); + return; + } + position += transferred; + } + return; + } + + copyBuffered(src, dst, copyBuffer()); + } + + private static void copyBuffered(ReadableByteChannel src, WritableByteChannel dst, ByteBuffer buffer) + throws IOException { + while (src.read(buffer) >= 0) { + buffer.flip(); + while (buffer.hasRemaining()) { + dst.write(buffer); + } + buffer.clear(); + } + } + + private static void drain(ReadableByteChannel src, long contentLength, ByteBuffer buffer) throws IOException { + if (contentLength < 0) { + while (src.read(buffer) >= 0) { + buffer.clear(); + } + return; + } + + long remaining = contentLength; + while (remaining > 0) { + buffer.clear(); + if (remaining < buffer.capacity()) { + buffer.limit((int) remaining); + } + int read = src.read(buffer); + if (read < 0) { + break; + } + remaining -= read; + } + } +} diff --git a/io/src/main/java/software/amazon/smithy/java/io/datastream/DataStream.java b/io/src/main/java/software/amazon/smithy/java/io/datastream/DataStream.java index 0926d60203..25b880c24b 100644 --- a/io/src/main/java/software/amazon/smithy/java/io/datastream/DataStream.java +++ b/io/src/main/java/software/amazon/smithy/java/io/datastream/DataStream.java @@ -11,6 +11,9 @@ import java.io.UncheckedIOException; import java.net.http.HttpRequest; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -92,6 +95,12 @@ default boolean hasKnownLength() { * Implementations may override this to avoid intermediate InputStream allocation * (e.g., writing directly from a byte array or ByteBuffer). * + *

Flushing is part of this contract, not just an optimization. An implementation carrying discrete + * messages (e.g. an event stream) may flush after each, and transports turn each flush into a wire + * frame/chunk. A send-then-await-reply event protocol deadlocks if its messages are buffered instead, + * so transports should drain a body via {@code writeTo}, not {@code asInputStream().transferTo(out)} + * (which is byte-oriented and drops these boundaries). + * * @param out the output stream to write to * @throws IOException if an I/O error occurs */ @@ -115,6 +124,41 @@ default void discard() throws IOException { // no-op for in-memory backings } + /** + * Write the contents of this stream to a writable byte channel. + * + *

This is the zero-copy path for transferring data. Implementations backed by + * files can use {@code FileChannel.transferTo()} for kernel-level zero-copy. + * Implementations backed by ByteBuffers can write directly without intermediate copies. + * + * @param channel the channel to write to + * @throws IOException if an I/O error occurs + */ + default void writeTo(WritableByteChannel channel) throws IOException { + try (var is = asInputStream()) { + ByteBuffer buf = ByteBuffer.allocate(8192); + int n; + while ((n = is.read(buf.array(), 0, buf.capacity())) > 0) { + buf.position(0).limit(n); + while (buf.hasRemaining()) { + channel.write(buf); + } + } + } + } + + /** + * Get a readable byte channel for zero-copy consumption. + * + *

Implementations backed by files can return a {@code FileChannel} directly. + * The default wraps {@link #asInputStream()} via {@code Channels.newChannel()}. + * + * @return a readable byte channel + */ + default ReadableByteChannel asChannel() { + return Channels.newChannel(asInputStream()); + } + /** * Read the contents of the stream into a ByteBuffer by reading all bytes from {@link #asInputStream()}. * @@ -204,6 +248,39 @@ static DataStream ofInputStream(InputStream inputStream, String contentType, lon return new InputStreamDataStream(inputStream, contentType, contentLength); } + /** + * Create a non-replayable DataStream from a readable channel. + * + * @param channel channel to wrap. + * @return the created DataStream. + */ + static DataStream ofChannel(ReadableByteChannel channel) { + return ofChannel(channel, null); + } + + /** + * Create a non-replayable DataStream from a readable channel. + * + * @param channel channel to wrap. + * @param contentType Content-Type of the stream if known, or null. + * @return the created DataStream. + */ + static DataStream ofChannel(ReadableByteChannel channel, String contentType) { + return ofChannel(channel, contentType, -1); + } + + /** + * Create a non-replayable DataStream from a readable channel. + * + * @param channel channel to wrap. + * @param contentType Content-Type of the stream if known, or null. + * @param contentLength Bytes in the stream if known, or -1. + * @return the created DataStream. + */ + static DataStream ofChannel(ReadableByteChannel channel, String contentType, long contentLength) { + return new ChannelDataStream(channel, contentType, contentLength); + } + /** * Create a DataStream from an in-memory UTF-8 string. * diff --git a/io/src/main/java/software/amazon/smithy/java/io/datastream/EmptyDataStream.java b/io/src/main/java/software/amazon/smithy/java/io/datastream/EmptyDataStream.java index 3e88b96934..d8ee282c0d 100644 --- a/io/src/main/java/software/amazon/smithy/java/io/datastream/EmptyDataStream.java +++ b/io/src/main/java/software/amazon/smithy/java/io/datastream/EmptyDataStream.java @@ -8,6 +8,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicBoolean; @@ -61,6 +64,16 @@ public void writeTo(OutputStream out) { // No-op } + @Override + public void writeTo(WritableByteChannel channel) { + // No-op + } + + @Override + public ReadableByteChannel asChannel() { + return Channels.newChannel(InputStream.nullInputStream()); + } + @Override public boolean isReplayable() { return true; diff --git a/io/src/main/java/software/amazon/smithy/java/io/datastream/FileDataStream.java b/io/src/main/java/software/amazon/smithy/java/io/datastream/FileDataStream.java index bc8069ffed..02f6a68b1a 100644 --- a/io/src/main/java/software/amazon/smithy/java/io/datastream/FileDataStream.java +++ b/io/src/main/java/software/amazon/smithy/java/io/datastream/FileDataStream.java @@ -7,11 +7,16 @@ import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.UncheckedIOException; import java.net.http.HttpRequest; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.concurrent.Flow; final class FileDataStream implements DataStream { @@ -60,6 +65,50 @@ public InputStream asInputStream() { } } + @Override + public ReadableByteChannel asChannel() { + try { + return FileChannel.open(file, StandardOpenOption.READ); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public void writeTo(OutputStream out) throws IOException { + try (InputStream in = asInputStream()) { + in.transferTo(out); + } + } + + @Override + public void writeTo(WritableByteChannel channel) throws IOException { + try (FileChannel fileChannel = FileChannel.open(file, StandardOpenOption.READ)) { + long position = 0; + long size = fileChannel.size(); + while (position < size) { + long transferred = fileChannel.transferTo(position, size - position, channel); + if (transferred <= 0) { + fileChannel.position(position); + copyRemaining(fileChannel, channel); + break; + } + position += transferred; + } + } + } + + private static void copyRemaining(FileChannel fileChannel, WritableByteChannel channel) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(8192); + while (fileChannel.read(buffer) >= 0) { + buffer.flip(); + while (buffer.hasRemaining()) { + channel.write(buffer); + } + buffer.clear(); + } + } + @Override public long contentLength() { return publisher.contentLength(); diff --git a/io/src/main/java/software/amazon/smithy/java/io/datastream/WrappedDataStream.java b/io/src/main/java/software/amazon/smithy/java/io/datastream/WrappedDataStream.java index d70924e69c..1fd3d4b843 100644 --- a/io/src/main/java/software/amazon/smithy/java/io/datastream/WrappedDataStream.java +++ b/io/src/main/java/software/amazon/smithy/java/io/datastream/WrappedDataStream.java @@ -9,6 +9,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.util.concurrent.Flow; final class WrappedDataStream implements DataStream { @@ -50,6 +52,16 @@ public void discard() throws IOException { delegate.discard(); } + @Override + public void writeTo(WritableByteChannel channel) throws IOException { + delegate.writeTo(channel); + } + + @Override + public ReadableByteChannel asChannel() { + return delegate.asChannel(); + } + @Override public long contentLength() { return contentLength; diff --git a/io/src/test/java/software/amazon/smithy/java/io/datastream/ChannelDataStreamTest.java b/io/src/test/java/software/amazon/smithy/java/io/datastream/ChannelDataStreamTest.java new file mode 100644 index 0000000000..4bdde6ed2f --- /dev/null +++ b/io/src/test/java/software/amazon/smithy/java/io/datastream/ChannelDataStreamTest.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.io.datastream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import org.junit.jupiter.api.Test; + +class ChannelDataStreamTest { + + @Test + void asChannelReadsFromChannel() throws Exception { + DataStream dataStream = DataStream.ofChannel(new TrackingChannel(new byte[] {1, 2, 3})); + + ByteBuffer dst = ByteBuffer.allocate(3); + + assertEquals(3, dataStream.asChannel().read(dst)); + assertEquals(ByteBuffer.wrap(new byte[] {1, 2, 3}), dst.flip()); + } + + @Test + void asChannelConsumesStream() { + DataStream dataStream = DataStream.ofChannel(new TrackingChannel(new byte[0])); + + dataStream.asChannel(); + + assertFalse(dataStream.isAvailable()); + assertThrows(IllegalStateException.class, dataStream::asInputStream); + } + + @Test + void closeClosesCreatedChannel() { + var channel = new TrackingChannel(new byte[] {1}); + DataStream dataStream = DataStream.ofChannel(channel); + + dataStream.close(); + + assertTrue(channel.closed); + } + + @Test + void writeToOutputStreamCopiesFromChannel() throws IOException { + DataStream dataStream = DataStream.ofChannel(new TrackingChannel(new byte[] {1, 2, 3})); + var out = new ByteArrayOutputStream(); + + dataStream.writeTo(out); + + assertEquals(ByteBuffer.wrap(new byte[] {1, 2, 3}), ByteBuffer.wrap(out.toByteArray())); + } + + @Test + void discardDrainsAndClosesChannel() throws IOException { + var channel = new TrackingChannel(new byte[] {1, 2, 3}); + DataStream dataStream = DataStream.ofChannel(channel); + + dataStream.discard(); + + assertFalse(dataStream.isAvailable()); + assertTrue(channel.closed); + assertFalse(channel.data.hasRemaining()); + } + + @Test + void discardKnownLengthDrainsOnlyContentLength() throws IOException { + var channel = new TrackingChannel(new byte[] {1, 2, 3, 4}); + DataStream dataStream = DataStream.ofChannel(channel, null, 2); + + dataStream.discard(); + + assertTrue(channel.closed); + assertEquals(2, channel.data.position()); + } + + private static final class TrackingChannel implements ReadableByteChannel { + private final ByteBuffer data; + private boolean closed; + + TrackingChannel(byte[] bytes) { + data = ByteBuffer.wrap(bytes); + } + + @Override + public int read(ByteBuffer dst) { + if (!data.hasRemaining()) { + return -1; + } + int toCopy = Math.min(data.remaining(), dst.remaining()); + int oldLimit = data.limit(); + data.limit(data.position() + toCopy); + dst.put(data); + data.limit(oldLimit); + return toCopy; + } + + @Override + public boolean isOpen() { + return !closed; + } + + @Override + public void close() { + closed = true; + } + } +} diff --git a/rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolver.java b/rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolver.java index eec2ee20f9..6fc1419a90 100644 --- a/rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolver.java +++ b/rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolver.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.function.Function; import software.amazon.smithy.java.context.Context; import software.amazon.smithy.java.endpoints.Endpoint; @@ -21,11 +22,14 @@ public final class BytecodeEndpointResolver implements EndpointResolver { private static final InternalLogger LOGGER = InternalLogger.getLogger(BytecodeEndpointResolver.class); + private static final int MAX_PROBE = 3; + private final Bytecode bytecode; private final RulesExtension[] extensions; private final RegisterFiller registerFiller; private final ContextProvider ctxProvider = new ContextProvider.OrchestratingProvider(); - private final ThreadLocal threadLocalEvaluator; + private final AtomicReferenceArray pool; + private final int poolMask; public BytecodeEndpointResolver( Bytecode bytecode, @@ -35,11 +39,15 @@ public BytecodeEndpointResolver( this.bytecode = bytecode; this.extensions = extensions.toArray(new RulesExtension[0]); - // Create and reuse this register filler across thread local evaluators. + // Create and reuse this register filler across pooled evaluators. this.registerFiller = RegisterFiller.of(bytecode, builtinProviders); - this.threadLocalEvaluator = ThreadLocal.withInitial(() -> { - return new BytecodeEvaluator(bytecode, this.extensions, registerFiller); - }); + + // Slots = next power of two >= cores*4, matching the JSON serializer pool sizing so a + // burst of concurrent resolves rarely overflows to allocation. + int raw = Runtime.getRuntime().availableProcessors() * 4; + int slots = Integer.highestOneBit(Math.max(raw - 1, 1)) << 1; + this.pool = new AtomicReferenceArray<>(slots); + this.poolMask = slots - 1; } public Bytecode getBytecode() { @@ -48,22 +56,55 @@ public Bytecode getBytecode() { @Override public Endpoint resolveEndpoint(EndpointResolverParams params) { - var evaluator = threadLocalEvaluator.get(); var operation = params.operation(); var ctx = params.context(); - // Write endpoint params into the register sink - var sink = evaluator.registerSink; - ContextProvider.createEndpointParams(sink, ctxProvider, ctx, operation, params.inputValue()); + // Per-thread, contention-free probe base (final-field read), shared by acquire and release. + int base = (int) Thread.currentThread().threadId(); + + BytecodeEvaluator evaluator = acquire(base); + try { + // Write endpoint params into the register sink + var sink = evaluator.registerSink; + ContextProvider.createEndpointParams(sink, ctxProvider, ctx, operation, params.inputValue()); + + // Reset the evaluator and prepare new registers from the sink. + evaluator.resetFromSink(ctx); - // Reset the evaluator and prepare new registers from the sink. - evaluator.resetFromSink(ctx); + LOGGER.debug("Resolving endpoint of {} using VM", operation); - LOGGER.debug("Resolving endpoint of {} using VM", operation); + var traceSink = ctx.get(RulesEngineSettings.BDD_TRACE_SINK); + return traceSink != null + ? evaluator.evaluateBddTraced(traceSink) + : evaluator.evaluateBdd(); + } finally { + // Recycle for the next resolve. resetFromSink fully reinitializes per-resolve state, so a + // stale evaluator carries nothing across uses; the Endpoint just returned holds no + // reference into it. + release(evaluator, base); + } + } + + private BytecodeEvaluator acquire(int base) { + for (int i = 0; i < MAX_PROBE; i++) { + int idx = (base + i) & poolMask; + BytecodeEvaluator e = pool.getPlain(idx); + // Acquire semantics: ensure we see the evaluator's fully-written state from its releaser. + if (e != null && pool.compareAndExchangeAcquire(idx, e, null) == e) { + return e; + } + } + return new BytecodeEvaluator(bytecode, extensions, registerFiller); + } - var traceSink = ctx.get(RulesEngineSettings.BDD_TRACE_SINK); - return traceSink != null - ? evaluator.evaluateBddTraced(traceSink) - : evaluator.evaluateBdd(); + private void release(BytecodeEvaluator evaluator, int base) { + for (int i = 0; i < MAX_PROBE; i++) { + int idx = (base + i) & poolMask; + // Release semantics: publish all evaluator state to a thread that later acquires it. + if (pool.getPlain(idx) == null && pool.compareAndExchangeRelease(idx, null, evaluator) == null) { + return; + } + } + // Pool full — let GC collect this evaluator. } } diff --git a/rulesengine/src/test/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolverTest.java b/rulesengine/src/test/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolverTest.java index d57336b019..c12b936588 100644 --- a/rulesengine/src/test/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolverTest.java +++ b/rulesengine/src/test/java/software/amazon/smithy/java/rulesengine/BytecodeEndpointResolverTest.java @@ -16,6 +16,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.function.Function; import java.util.stream.Collectors; import org.junit.jupiter.api.Assertions; @@ -641,6 +644,71 @@ public void result(int resultId, Endpoint endpoint) { } } + @Test + void concurrentResolutionsReuseEvaluatorsWithoutCrossTalk() throws Exception { + // Resolve distinct inputs from many threads at once. The evaluator pool recycles evaluators + // across calls, so this guards that a recycled evaluator never leaks one call's register + // state into another: every result must match its own input. + RegisterDefinition[] defs = { + new RegisterDefinition("region", false, null, null, false), + new RegisterDefinition("bucket", false, null, null, false) + }; + Bytecode bytecode = new Bytecode( + new byte[] { + Opcodes.LOAD_REGISTER, + 0, // region + Opcodes.LOAD_CONST, + 0, // "/" + Opcodes.LOAD_REGISTER, + 1, // bucket + Opcodes.RESOLVE_TEMPLATE, + 3, + Opcodes.RETURN_ENDPOINT, + 0 + }, + new int[0], + new int[] {0}, + defs, + new Object[] {"/"}, + new RulesFunction[0], + new int[] {-1, 100_000_000, -1}, + 100_000_000); + + BytecodeEndpointResolver resolver = new BytecodeEndpointResolver(bytecode, List.of(), Map.of()); + + int threads = 16; + int perThread = 500; + var pool = Executors.newFixedThreadPool(threads); + try { + var start = new CountDownLatch(1); + var futures = new ArrayList>(); + for (int t = 0; t < threads; t++) { + final int id = t; + futures.add(pool.submit(() -> { + String region = "r" + id; + String bucket = "b" + id; + String expected = region + "/" + bucket; + try { + start.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + for (int i = 0; i < perThread; i++) { + Endpoint endpoint = resolver.resolveEndpoint(createParams(region, bucket)); + assertEquals(expected, endpoint.uri().toString()); + } + })); + } + start.countDown(); + for (var f : futures) { + f.get(); // propagates any assertion failure + } + } finally { + pool.shutdownNow(); + } + } + // Helper methods /** diff --git a/settings.gradle.kts b/settings.gradle.kts index 6040db584f..b9e5a8fe94 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -49,6 +49,8 @@ include(":client:client-auth-api") include(":client:client-http") include(":client:client-http-binding") include(":client:client-rpcv2") +include(":client:client-http-smithy") +include(":client:client-http-boringssl") include(":client:client-rpcv2-cbor") include(":client:client-rpcv2-json") include(":client:dynamic-client")