private boolean validateHeader(Fields headers, String name, String expectedValue) {
   Fields.Field header = headers.get(name);
   if (header != null && expectedValue.equals(header.value())) return true;
   System.out.println(
       name + " not valid! Expected: " + expectedValue + " headers received:" + headers);
   return false;
 }
  public ByteBuffer generate(short version, Fields headers) {
    // TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using
    // ByteBuffer ?
    final Charset iso1 = StandardCharsets.ISO_8859_1;
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.getSize() * 64);
    writeCount(version, buffer, headers.getSize());
    for (Fields.Field header : headers) {
      String name = header.getName().toLowerCase(Locale.ENGLISH);
      byte[] nameBytes = name.getBytes(iso1);
      writeNameLength(version, buffer, nameBytes.length);
      buffer.write(nameBytes, 0, nameBytes.length);

      // Most common path first
      String value = header.getValue();
      byte[] valueBytes = value.getBytes(iso1);
      if (header.hasMultipleValues()) {
        List<String> values = header.getValues();
        for (int i = 1; i < values.size(); ++i) {
          byte[] moreValueBytes = values.get(i).getBytes(iso1);
          byte[] newValueBytes = new byte[valueBytes.length + 1 + moreValueBytes.length];
          System.arraycopy(valueBytes, 0, newValueBytes, 0, valueBytes.length);
          newValueBytes[valueBytes.length] = 0;
          System.arraycopy(
              moreValueBytes, 0, newValueBytes, valueBytes.length + 1, moreValueBytes.length);
          valueBytes = newValueBytes;
        }
      }

      writeValueLength(version, buffer, valueBytes.length);
      buffer.write(valueBytes, 0, valueBytes.length);
    }

    return compress(version, buffer.toByteArray());
  }
 public boolean isUserAgentBlacklisted(Fields headers) {
   Fields.Field userAgentHeader = headers.get("user-agent");
   if (userAgentHeader != null)
     for (Pattern userAgentPattern : userAgentBlacklist)
       if (userAgentPattern.matcher(userAgentHeader.getValue()).matches()) return true;
   return false;
 }
  @Override
  public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders) {
    Set<String> result = Collections.<String>emptySet();
    short version = stream.getSession().getVersion();
    if (!isIfModifiedSinceHeaderPresent(requestHeaders)
        && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).getValue())
        && !isUserAgentBlacklisted(requestHeaders)) {
      String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).getValue();
      String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).getValue();
      String origin = scheme + "://" + host;
      String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).getValue();
      String absoluteURL = origin + url;
      if (LOG.isDebugEnabled()) LOG.debug("Applying push strategy for {}", absoluteURL);
      if (isMainResource(url, responseHeaders)) {
        MainResource mainResource = getOrCreateMainResource(absoluteURL);
        result = mainResource.getResources();
      } else if (isPushResource(url, responseHeaders)) {
        Fields.Field referrerHeader = requestHeaders.get("referer");
        if (referrerHeader != null) {
          String referrer = referrerHeader.getValue();
          MainResource mainResource = mainResources.get(referrer);
          if (mainResource == null) mainResource = getOrCreateMainResource(referrer);

          Set<String> pushResources = mainResource.getResources();
          if (!pushResources.contains(url)) mainResource.addResource(url, origin, referrer);
          else result = getPushResources(absoluteURL);
        }
      }
      if (LOG.isDebugEnabled())
        LOG.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result);
    }
    return result;
  }
 private boolean validateUriHeader(Fields headers) {
   Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version));
   if (uriHeader != null)
     if (version == SPDY.V2 && uriHeader.value().startsWith("http://")) return true;
     else if (version == SPDY.V3
         && uriHeader.value().startsWith("/")
         && headers.get(HTTPSPDYHeader.HOST.name(version)) != null
         && headers.get(HTTPSPDYHeader.SCHEME.name(version)) != null) return true;
   System.out.println(HTTPSPDYHeader.URI.name(version) + " not valid!");
   return false;
 }
  private boolean isPushResource(String url, Fields responseHeaders) {
    for (Pattern pushRegexp : pushRegexps) {
      if (pushRegexp.matcher(url).matches()) {
        Fields.Field header = responseHeaders.get("content-type");
        if (header == null) return true;

        String contentType = header.getValue().toLowerCase(Locale.ENGLISH);
        for (String pushContentType : pushContentTypes)
          if (contentType.startsWith(pushContentType)) return true;
      }
    }
    return false;
  }
  private static ByteBuffer convertFields(String contentDisposition, Fields fields) {
    try {
      if (fields == null || fields.isEmpty()) {
        contentDisposition += "\r\n";
        return ByteBuffer.wrap(contentDisposition.getBytes(StandardCharsets.US_ASCII));
      }

      ByteArrayOutputStream buffer =
          new ByteArrayOutputStream((fields.getSize() + 1) * contentDisposition.length());
      buffer.write(contentDisposition.getBytes(StandardCharsets.US_ASCII));
      for (Fields.Field field : fields) {
        buffer.write(field.getName().getBytes(StandardCharsets.US_ASCII));
        buffer.write(COLON_SPACE_BYTES);
        buffer.write(field.getValue().getBytes(StandardCharsets.UTF_8));
        buffer.write(CR_LF_BYTES);
      }
      buffer.write(CR_LF_BYTES);
      return ByteBuffer.wrap(buffer.toByteArray());
    } catch (IOException x) {
      throw new RuntimeIOException(x);
    }
  }
  @Override
  public void onReply(Stream stream, ReplyInfo replyInfo) {
    HttpExchange exchange = getHttpExchange();
    if (exchange == null) return;

    try {
      HttpResponse response = exchange.getResponse();

      Fields fields = replyInfo.getHeaders();
      short spdy = stream.getSession().getVersion();
      HttpVersion version =
          HttpVersion.fromString(fields.get(HTTPSPDYHeader.VERSION.name(spdy)).getValue());
      response.version(version);
      String[] status = fields.get(HTTPSPDYHeader.STATUS.name(spdy)).getValue().split(" ", 2);

      Integer code = Integer.parseInt(status[0]);
      response.status(code);
      String reason = status.length < 2 ? HttpStatus.getMessage(code) : status[1];
      response.reason(reason);

      if (responseBegin(exchange)) {
        for (Fields.Field field : fields) {
          String name = field.getName();
          if (HTTPSPDYHeader.from(spdy, name) != null) continue;
          // TODO: handle multiple values properly
          HttpField httpField = new HttpField(name, field.getValue());
          responseHeader(exchange, httpField);
        }

        if (responseHeaders(exchange)) {
          if (replyInfo.isClose()) {
            responseSuccess(exchange);
          }
        }
      }
    } catch (Exception x) {
      responseFailure(x);
    }
  }
    @Override
    public void reply(ReplyInfo replyInfo, Callback handler) {
      try {
        Fields headers = new Fields(replyInfo.getHeaders(), false);

        headers.remove(HTTPSPDYHeader.SCHEME.name(version));

        String status = headers.remove(HTTPSPDYHeader.STATUS.name(version)).value();
        Matcher matcher = statusRegexp.matcher(status);
        matcher.matches();
        int code = Integer.parseInt(matcher.group(1));
        String reason = matcher.group(2).trim();

        HttpVersion httpVersion =
            HttpVersion.fromString(headers.remove(HTTPSPDYHeader.VERSION.name(version)).value());

        // Convert the Host header from a SPDY special header to a normal header
        Fields.Field host = headers.remove(HTTPSPDYHeader.HOST.name(version));
        if (host != null) headers.put("host", host.value());

        HttpFields fields = new HttpFields();
        for (Fields.Field header : headers) {
          String name = camelize(header.name());
          fields.put(name, header.value());
        }

        // TODO: handle better the HEAD last parameter
        HttpGenerator.ResponseInfo info =
            new HttpGenerator.ResponseInfo(httpVersion, fields, -1, code, reason, false);
        send(info, null, replyInfo.isClose());

        if (replyInfo.isClose()) completed();

        handler.succeeded();
      } catch (IOException x) {
        handler.failed(x);
      }
    }