From 2155251b2a83e60121b16b38c87e2f14ea65bc85 Mon Sep 17 00:00:00 2001 From: hieplq Date: Sat, 22 Apr 2017 12:27:40 +0700 Subject: [PATCH] IDEMPIERE-3136:update jetty to 9.4.x jetty resolved hpack issue here, so isn't need work-around https://github.com/eclipse/jetty.project/issues/1290 Atmosphere don't compactible with new jetty https://github.com/Atmosphere/atmosphere/issues/2242 SessionManager is removed: http://www.eclipse.org/jetty/documentation/9.4.x/session-management.html http://www.eclipse.org/jetty/documentation/9.3.0.v20150612/session-management.html --- org.adempiere.sdk-feature/adempiere.cquery | 10 +- org.adempiere.sdk-feature/adempiere.rmap | 1 - .../jettyhome/etc/jetty-http2.xml | 2 +- org.adempiere.server-feature/server.product | 4 + org.eclipse.jetty.http/.classpath | 7 - org.eclipse.jetty.http/.project | 33 - org.eclipse.jetty.http/META-INF/MANIFEST.MF | 35 - ...org.eclipse.jetty.http.HttpFieldPreEncoder | 2 - org.eclipse.jetty.http/about.html | 27 - org.eclipse.jetty.http/build.properties | 4 - .../jetty/http/BadMessageException.java | 71 - .../org/eclipse/jetty/http/DateGenerator.java | 173 -- .../org/eclipse/jetty/http/DateParser.java | 109 - .../eclipse/jetty/http/GzipHttpContent.java | 188 -- .../eclipse/jetty/http/HostPortHttpField.java | 106 - .../jetty/http/Http1FieldPreEncoder.java | 69 - .../eclipse/jetty/http/HttpCompliance.java | 32 - .../org/eclipse/jetty/http/HttpContent.java | 80 - .../org/eclipse/jetty/http/HttpCookie.java | 164 -- .../src/org/eclipse/jetty/http/HttpField.java | 510 ----- .../jetty/http/HttpFieldPreEncoder.java | 36 - .../org/eclipse/jetty/http/HttpFields.java | 970 --------- .../org/eclipse/jetty/http/HttpGenerator.java | 1023 ---------- .../org/eclipse/jetty/http/HttpHeader.java | 191 -- .../eclipse/jetty/http/HttpHeaderValue.java | 104 - .../org/eclipse/jetty/http/HttpMethod.java | 187 -- .../org/eclipse/jetty/http/HttpParser.java | 1802 ----------------- .../org/eclipse/jetty/http/HttpScheme.java | 79 - .../org/eclipse/jetty/http/HttpStatus.java | 1076 ---------- .../org/eclipse/jetty/http/HttpTokens.java | 38 - .../src/org/eclipse/jetty/http/HttpURI.java | 783 ------- .../org/eclipse/jetty/http/HttpVersion.java | 173 -- .../src/org/eclipse/jetty/http/MetaData.java | 298 --- .../src/org/eclipse/jetty/http/MimeTypes.java | 497 ----- .../src/org/eclipse/jetty/http/PathMap.java | 641 ------ .../jetty/http/PreEncodedHttpField.java | 94 - .../src/org/eclipse/jetty/http/QuotedCSV.java | 229 --- .../eclipse/jetty/http/QuotedQualityCSV.java | 252 --- .../jetty/http/ResourceHttpContent.java | 227 --- .../eclipse/jetty/http/encoding.properties | 5 - .../org/eclipse/jetty/http/mime.properties | 189 -- .../org/eclipse/jetty/http/package-info.java | 23 - .../jetty/http/pathmap/MappedResource.java | 101 - .../jetty/http/pathmap/PathMappings.java | 159 -- .../eclipse/jetty/http/pathmap/PathSpec.java | 167 -- .../jetty/http/pathmap/PathSpecGroup.java | 101 - .../jetty/http/pathmap/PathSpecSet.java | 222 -- .../jetty/http/pathmap/RegexPathSpec.java | 176 -- .../jetty/http/pathmap/ServletPathSpec.java | 261 --- .../http/pathmap/UriTemplatePathSpec.java | 341 ---- .../jetty/http2/hpack/AuthorityHttpField.java | 43 - .../jetty/http2/hpack/HpackContext.java | 515 ----- .../jetty/http2/hpack/HpackDecoder.java | 280 --- .../jetty/http2/hpack/HpackEncoder.java | 354 ---- .../http2/hpack/HpackFieldPreEncoder.java | 97 - .../eclipse/jetty/http2/hpack/Huffman.java | 480 ----- .../jetty/http2/hpack/MetaDataBuilder.java | 184 -- .../jetty/http2/hpack/NBitInteger.java | 151 -- .../http2/hpack/StaticTableHttpField.java | 61 - 59 files changed, 10 insertions(+), 14227 deletions(-) delete mode 100644 org.eclipse.jetty.http/.classpath delete mode 100644 org.eclipse.jetty.http/.project delete mode 100644 org.eclipse.jetty.http/META-INF/MANIFEST.MF delete mode 100644 org.eclipse.jetty.http/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder delete mode 100644 org.eclipse.jetty.http/about.html delete mode 100644 org.eclipse.jetty.http/build.properties delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/BadMessageException.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateGenerator.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateParser.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/GzipHttpContent.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HostPortHttpField.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/Http1FieldPreEncoder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCompliance.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpContent.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCookie.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpField.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFieldPreEncoder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFields.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpGenerator.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeader.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeaderValue.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpMethod.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpParser.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpScheme.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpStatus.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpTokens.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpURI.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpVersion.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/MetaData.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/MimeTypes.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/PathMap.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/PreEncodedHttpField.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/QuotedCSV.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/QuotedQualityCSV.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/ResourceHttpContent.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/encoding.properties delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/mime.properties delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/package-info.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/MappedResource.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathMappings.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpec.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecGroup.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecSet.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/RegexPathSpec.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/ServletPathSpec.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackContext.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackDecoder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackEncoder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/Huffman.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/NBitInteger.java delete mode 100644 org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java diff --git a/org.adempiere.sdk-feature/adempiere.cquery b/org.adempiere.sdk-feature/adempiere.cquery index 8a6216cf0f0..ffac686c820 100644 --- a/org.adempiere.sdk-feature/adempiere.cquery +++ b/org.adempiere.sdk-feature/adempiere.cquery @@ -8,10 +8,10 @@ - - - - - + + + + + diff --git a/org.adempiere.sdk-feature/adempiere.rmap b/org.adempiere.sdk-feature/adempiere.rmap index 8fbc27af925..6843a9b0c85 100644 --- a/org.adempiere.sdk-feature/adempiere.rmap +++ b/org.adempiere.sdk-feature/adempiere.rmap @@ -5,7 +5,6 @@ - diff --git a/org.adempiere.server-feature/jettyhome/etc/jetty-http2.xml b/org.adempiere.server-feature/jettyhome/etc/jetty-http2.xml index 1785854c38d..1ce8c2ff3ab 100644 --- a/org.adempiere.server-feature/jettyhome/etc/jetty-http2.xml +++ b/org.adempiere.server-feature/jettyhome/etc/jetty-http2.xml @@ -10,7 +10,7 @@ - + diff --git a/org.adempiere.server-feature/server.product b/org.adempiere.server-feature/server.product index 1c10ea8ed54..db3d939abb7 100644 --- a/org.adempiere.server-feature/server.product +++ b/org.adempiere.server-feature/server.product @@ -61,6 +61,10 @@ + + + + diff --git a/org.eclipse.jetty.http/.classpath b/org.eclipse.jetty.http/.classpath deleted file mode 100644 index ed0eb24c506..00000000000 --- a/org.eclipse.jetty.http/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.eclipse.jetty.http/.project b/org.eclipse.jetty.http/.project deleted file mode 100644 index dd72cce6c0b..00000000000 --- a/org.eclipse.jetty.http/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - org.eclipse.jetty.http - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - org.eclipse.pde.ds.core.builder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.eclipse.jetty.http/META-INF/MANIFEST.MF b/org.eclipse.jetty.http/META-INF/MANIFEST.MF deleted file mode 100644 index 91b423aa8af..00000000000 --- a/org.eclipse.jetty.http/META-INF/MANIFEST.MF +++ /dev/null @@ -1,35 +0,0 @@ -Manifest-Version: 1.0 -Archiver-Version: Plexus Archiver -Created-By: Apache Maven Bundle Plugin -Built-By: joakim -Build-Jdk: 1.8.0_65 -Implementation-Vendor: Eclipse.org - Jetty -Implementation-Version: 9.3.10.v20160621 -url: http://www.eclipse.org/jetty -Bnd-LastModified: 1457969504223 -Bundle-Classpath: . -Bundle-Copyright: Copyright (c) 2008-2016 Mort Bay Consulting Pty. Ltd. -Bundle-Description: Jetty module for Jetty :: Http Utility -Bundle-DocURL: http://www.eclipse.org/jetty -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0, http://www - .eclipse.org/org/documents/epl-v10.php -Bundle-ManifestVersion: 2 -Bundle-Name: Jetty :: Http Utility -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Bundle-SymbolicName: org.eclipse.jetty.http -Bundle-Vendor: Eclipse Jetty Project -Bundle-Version: 9.3.10.v20160621 -Export-Package: org.eclipse.jetty.http;version="9.3.10";uses:="org.ecl - ipse.jetty.util,org.eclipse.jetty.util.log,org.eclipse.jetty.util.res - ource",org.eclipse.jetty.http.pathmap;version="9.3.10";uses:="org.ecl - ipse.jetty.util.annotation,org.eclipse.jetty.util.component",org.ecli - pse.jetty.http2.hpack;version="9.3.10";uses:="org.eclipse.jetty.http, - org.eclipse.jetty.util.log" -Import-Package: org.eclipse.jetty.util;version="[9.3.10,9.3.11)",org.e - clipse.jetty.util.annotation;version="[9.3.10,9.3.11)",org.eclipse.je - tty.util.component;version="[9.3.10,9.3.11)",org.eclipse.jetty.util.l - og;version="[9.3.10,9.3.11)",org.eclipse.jetty.util.resource;version= - "[9.3.10,9.3.11)" -Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" -Tool: Bnd-2.4.1.201501161923 - diff --git a/org.eclipse.jetty.http/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder b/org.eclipse.jetty.http/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder deleted file mode 100644 index 0da39aad7a6..00000000000 --- a/org.eclipse.jetty.http/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder +++ /dev/null @@ -1,2 +0,0 @@ -org.eclipse.jetty.http.Http1FieldPreEncoder -org.eclipse.jetty.http2.hpack.HpackFieldPreEncoder diff --git a/org.eclipse.jetty.http/about.html b/org.eclipse.jetty.http/about.html deleted file mode 100644 index e13b48d47f6..00000000000 --- a/org.eclipse.jetty.http/about.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - -About - - -

About This Content

- -

19 May, 2009

-

License

- -

The Eclipse Foundation makes available all content in this plug-in ("Content"). The Content is dual licensed and is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 ("EPL") as well as the Apache Software License Version 2.0. A copy of the EPL is available -at http://www.eclipse.org/legal/epl-v10.html. A copy of the ASL is available at http://www.apache.org/licenses/LICENSE-2.0.html. For purposes of the EPL, "Program" will mean the Content.

- -

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

- -

jetty-util artifact only:

The UnixCrypt.java code implements the one way cryptography used by -Unix systems for simple password protection. Copyright 1996 Aki Yoshida, -modified April 2001 by Iris Van den Broeke, Daniel Deville. -Permission to use, copy, modify and distribute UnixCrypt -for non-commercial or commercial purposes and without fee is -granted provided that the copyright notice appears in all copies.

- - - diff --git a/org.eclipse.jetty.http/build.properties b/org.eclipse.jetty.http/build.properties deleted file mode 100644 index 34d2e4d2dad..00000000000 --- a/org.eclipse.jetty.http/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/BadMessageException.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/BadMessageException.java deleted file mode 100644 index c3a68d8ef96..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/BadMessageException.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -/* ------------------------------------------------------------------------------- */ -/** - *

Exception thrown to indicate a Bad HTTP Message has either been received - * or attempted to be generated. Typically these are handled with either 400 - * or 500 responses.

- */ -@SuppressWarnings("serial") -public class BadMessageException extends RuntimeException -{ - final int _code; - final String _reason; - - public BadMessageException() - { - this(400,null); - } - - public BadMessageException(int code) - { - this(code,null); - } - - public BadMessageException(String reason) - { - this(400,reason); - } - - public BadMessageException(int code, String reason) - { - super(code+": "+reason); - _code=code; - _reason=reason; - } - - public BadMessageException(int code, String reason, Throwable cause) - { - super(code+": "+reason, cause); - _code=code; - _reason=reason; - } - - public int getCode() - { - return _code; - } - - public String getReason() - { - return _reason; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateGenerator.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateGenerator.java deleted file mode 100644 index 183b29f6b62..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateGenerator.java +++ /dev/null @@ -1,173 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -import org.eclipse.jetty.util.StringUtil; - -/** - * ThreadLocal Date formatters for HTTP style dates. - */ -public class DateGenerator -{ - private static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); - static - { - __GMT.setID("GMT"); - } - - static final String[] DAYS = - { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - static final String[] MONTHS = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"}; - - - private static final ThreadLocal __dateGenerator =new ThreadLocal() - { - @Override - protected DateGenerator initialValue() - { - return new DateGenerator(); - } - }; - - - public final static String __01Jan1970=DateGenerator.formatDate(0); - - /** - * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" - * @param date the date in milliseconds - * @return the formatted date - */ - public static String formatDate(long date) - { - return __dateGenerator.get().doFormatDate(date); - } - - /** - * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies - * @param buf the buffer to put the formatted date into - * @param date the date in milliseconds - */ - public static void formatCookieDate(StringBuilder buf, long date) - { - __dateGenerator.get().doFormatCookieDate(buf,date); - } - - /** - * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies - * @param date the date in milliseconds - * @return the formatted date - */ - public static String formatCookieDate(long date) - { - StringBuilder buf = new StringBuilder(28); - formatCookieDate(buf, date); - return buf.toString(); - } - - private final StringBuilder buf = new StringBuilder(32); - private final GregorianCalendar gc = new GregorianCalendar(__GMT); - - /** - * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" - * @param date the date in milliseconds - * @return the formatted date - */ - public String doFormatDate(long date) - { - buf.setLength(0); - gc.setTimeInMillis(date); - - int day_of_week = gc.get(Calendar.DAY_OF_WEEK); - int day_of_month = gc.get(Calendar.DAY_OF_MONTH); - int month = gc.get(Calendar.MONTH); - int year = gc.get(Calendar.YEAR); - int century = year / 100; - year = year % 100; - - int hours = gc.get(Calendar.HOUR_OF_DAY); - int minutes = gc.get(Calendar.MINUTE); - int seconds = gc.get(Calendar.SECOND); - - buf.append(DAYS[day_of_week]); - buf.append(','); - buf.append(' '); - StringUtil.append2digits(buf, day_of_month); - - buf.append(' '); - buf.append(MONTHS[month]); - buf.append(' '); - StringUtil.append2digits(buf, century); - StringUtil.append2digits(buf, year); - - buf.append(' '); - StringUtil.append2digits(buf, hours); - buf.append(':'); - StringUtil.append2digits(buf, minutes); - buf.append(':'); - StringUtil.append2digits(buf, seconds); - buf.append(" GMT"); - return buf.toString(); - } - - /** - * Format "EEE, dd-MMM-yy HH:mm:ss 'GMT'" for cookies - * @param buf the buffer to format the date into - * @param date the date in milliseconds - */ - public void doFormatCookieDate(StringBuilder buf, long date) - { - gc.setTimeInMillis(date); - - int day_of_week = gc.get(Calendar.DAY_OF_WEEK); - int day_of_month = gc.get(Calendar.DAY_OF_MONTH); - int month = gc.get(Calendar.MONTH); - int year = gc.get(Calendar.YEAR); - year = year % 10000; - - int epoch = (int) ((date / 1000) % (60 * 60 * 24)); - int seconds = epoch % 60; - epoch = epoch / 60; - int minutes = epoch % 60; - int hours = epoch / 60; - - buf.append(DAYS[day_of_week]); - buf.append(','); - buf.append(' '); - StringUtil.append2digits(buf, day_of_month); - - buf.append('-'); - buf.append(MONTHS[month]); - buf.append('-'); - StringUtil.append2digits(buf, year/100); - StringUtil.append2digits(buf, year%100); - - buf.append(' '); - StringUtil.append2digits(buf, hours); - buf.append(':'); - StringUtil.append2digits(buf, minutes); - buf.append(':'); - StringUtil.append2digits(buf, seconds); - buf.append(" GMT"); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateParser.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateParser.java deleted file mode 100644 index 8c95694071a..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/DateParser.java +++ /dev/null @@ -1,109 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/** - * ThreadLocal data parsers for HTTP style dates - * - */ -public class DateParser -{ - private static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); - static - { - __GMT.setID("GMT"); - } - - final static String __dateReceiveFmt[] = - { - "EEE, dd MMM yyyy HH:mm:ss zzz", - "EEE, dd-MMM-yy HH:mm:ss", - "EEE MMM dd HH:mm:ss yyyy", - - "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz", - "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss", - "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz", - "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz", - "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz", - "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz", - "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss", - }; - - public static long parseDate(String date) - { - return __dateParser.get().parse(date); - } - - private static final ThreadLocal __dateParser =new ThreadLocal() - { - @Override - protected DateParser initialValue() - { - return new DateParser(); - } - }; - - final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length]; - - private long parse(final String dateVal) - { - for (int i = 0; i < _dateReceive.length; i++) - { - if (_dateReceive[i] == null) - { - _dateReceive[i] = new SimpleDateFormat(__dateReceiveFmt[i], Locale.US); - _dateReceive[i].setTimeZone(__GMT); - } - - try - { - Date date = (Date) _dateReceive[i].parseObject(dateVal); - return date.getTime(); - } - catch (java.lang.Exception e) - { - // LOG.ignore(e); - } - } - - if (dateVal.endsWith(" GMT")) - { - final String val = dateVal.substring(0, dateVal.length() - 4); - - for (SimpleDateFormat element : _dateReceive) - { - try - { - Date date = (Date) element.parseObject(val); - return date.getTime(); - } - catch (java.lang.Exception e) - { - // LOG.ignore(e); - } - } - } - return -1; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/GzipHttpContent.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/GzipHttpContent.java deleted file mode 100644 index 3d237347a69..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/GzipHttpContent.java +++ /dev/null @@ -1,188 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; -import org.eclipse.jetty.http.MimeTypes.Type; - -import org.eclipse.jetty.util.resource.Resource; - -/* ------------------------------------------------------------ */ -public class GzipHttpContent implements HttpContent -{ - private final HttpContent _content; - private final HttpContent _contentGz; - public final static String ETAG_GZIP="--gzip"; - public final static String ETAG_GZIP_QUOTE="--gzip\""; - public final static PreEncodedHttpField CONTENT_ENCODING_GZIP=new PreEncodedHttpField(HttpHeader.CONTENT_ENCODING,"gzip"); - - public static String removeGzipFromETag(String etag) - { - if (etag==null) - return null; - int i = etag.indexOf(ETAG_GZIP_QUOTE); - if (i<0) - return etag; - return etag.substring(0,i)+'"'; - } - - public GzipHttpContent(HttpContent content, HttpContent contentGz) - { - _content=content; - _contentGz=contentGz; - } - - @Override - public int hashCode() - { - return _content.hashCode(); - } - - @Override - public boolean equals(Object obj) - { - return _content.equals(obj); - } - - @Override - public Resource getResource() - { - return _content.getResource(); - } - - @Override - public HttpField getETag() - { - return new HttpField(HttpHeader.ETAG,getETagValue()); - } - - @Override - public String getETagValue() - { - return _content.getResource().getWeakETag(ETAG_GZIP); - } - - @Override - public HttpField getLastModified() - { - return _content.getLastModified(); - } - - @Override - public String getLastModifiedValue() - { - return _content.getLastModifiedValue(); - } - - @Override - public HttpField getContentType() - { - return _content.getContentType(); - } - - @Override - public String getContentTypeValue() - { - return _content.getContentTypeValue(); - } - - @Override - public HttpField getContentEncoding() - { - return CONTENT_ENCODING_GZIP; - } - - @Override - public String getContentEncodingValue() - { - return CONTENT_ENCODING_GZIP.getValue(); - } - - @Override - public String getCharacterEncoding() - { - return _content.getCharacterEncoding(); - } - - @Override - public Type getMimeType() - { - return _content.getMimeType(); - } - - @Override - public void release() - { - _content.release(); - } - - @Override - public ByteBuffer getIndirectBuffer() - { - return _contentGz.getIndirectBuffer(); - } - - @Override - public ByteBuffer getDirectBuffer() - { - return _contentGz.getDirectBuffer(); - } - - @Override - public HttpField getContentLength() - { - return _contentGz.getContentLength(); - } - - @Override - public long getContentLengthValue() - { - return _contentGz.getContentLengthValue(); - } - - @Override - public InputStream getInputStream() throws IOException - { - return _contentGz.getInputStream(); - } - - @Override - public ReadableByteChannel getReadableByteChannel() throws IOException - { - return _contentGz.getReadableByteChannel(); - } - - @Override - public String toString() - { - return String.format("GzipHttpContent@%x{r=%s|%s,lm=%s|%s,ct=%s}",hashCode(), - _content.getResource(),_contentGz.getResource(), - _content.getResource().lastModified(),_contentGz.getResource().lastModified(), - getContentType()); - } - - @Override - public HttpContent getGzipContent() - { - return null; - } -} \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HostPortHttpField.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HostPortHttpField.java deleted file mode 100644 index 5818e138e5f..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HostPortHttpField.java +++ /dev/null @@ -1,106 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http; - -import org.eclipse.jetty.util.StringUtil; - - - -/* ------------------------------------------------------------ */ -/** - */ -public class HostPortHttpField extends HttpField -{ - private final String _host; - private final int _port; - - public HostPortHttpField(String authority) - { - this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); - } - - public HostPortHttpField(HttpHeader header, String name, String authority) - { - super(header,name,authority); - if (authority==null || authority.length()==0) - throw new IllegalArgumentException("No Authority"); - try - { - if (authority.charAt(0)=='[') - { - // ipv6reference - int close=authority.lastIndexOf(']'); - if (close<0) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); - _host=authority.substring(0,close+1); - - if (authority.length()>close+1) - { - if (authority.charAt(close+1)!=':') - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); - _port=StringUtil.toInt(authority,close+2); - } - else - _port=0; - } - else - { - // ipv4address or hostname - int c = authority.lastIndexOf(':'); - if (c>=0) - { - _host=authority.substring(0,c); - _port=StringUtil.toInt(authority,c+1); - } - else - { - _host=authority; - _port=0; - } - } - } - catch (BadMessageException bm) - { - throw bm; - } - catch(Exception e) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); - } - } - - /* ------------------------------------------------------------ */ - /** Get the host. - * @return the host - */ - public String getHost() - { - return _host; - } - - /* ------------------------------------------------------------ */ - /** Get the port. - * @return the port - */ - public int getPort() - { - return _port; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/Http1FieldPreEncoder.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/Http1FieldPreEncoder.java deleted file mode 100644 index aefb28159a1..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/Http1FieldPreEncoder.java +++ /dev/null @@ -1,69 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http; - -import static java.nio.charset.StandardCharsets.ISO_8859_1; - -import java.util.Arrays; - - -/* ------------------------------------------------------------ */ -/** - */ -public class Http1FieldPreEncoder implements HttpFieldPreEncoder -{ - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() - */ - @Override - public HttpVersion getHttpVersion() - { - return HttpVersion.HTTP_1_0; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String) - */ - @Override - public byte[] getEncodedField(HttpHeader header, String headerString, String value) - { - if (header!=null) - { - int cbl=header.getBytesColonSpace().length; - byte[] bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2); - System.arraycopy(value.getBytes(ISO_8859_1),0,bytes,cbl,value.length()); - bytes[bytes.length-2]=(byte)'\r'; - bytes[bytes.length-1]=(byte)'\n'; - return bytes; - } - - byte[] n=headerString.getBytes(ISO_8859_1); - byte[] v=value.getBytes(ISO_8859_1); - byte[] bytes=Arrays.copyOf(n,n.length+2+v.length+2); - bytes[n.length]=(byte)':'; - bytes[n.length]=(byte)' '; - bytes[bytes.length-2]=(byte)'\r'; - bytes[bytes.length-1]=(byte)'\n'; - - return bytes; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCompliance.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCompliance.java deleted file mode 100644 index 8a74370430f..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCompliance.java +++ /dev/null @@ -1,32 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - - -/** - * HTTP compliance modes: - *
- *
RFC7230
(default) Compliance with RFC7230
- *
RFC2616
Wrapped/Continued headers and HTTP/0.9 supported
- *
LEGACY
(aka STRICT) Adherence to Servlet Specification requirement for - * exact case of header names, bypassing the header caches, which are case insensitive, - * otherwise equivalent to RFC2616
- *
- */ -public enum HttpCompliance { LEGACY, RFC2616, RFC7230 } \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpContent.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpContent.java deleted file mode 100644 index 50871afede3..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpContent.java +++ /dev/null @@ -1,80 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; - -import org.eclipse.jetty.http.MimeTypes.Type; -import org.eclipse.jetty.util.resource.Resource; - -/* ------------------------------------------------------------ */ -/** HttpContent interface. - *

This information represents all the information about a - * static resource that is needed to evaluate conditional headers - * and to serve the content if need be. It can be implemented - * either transiently (values and fields generated on demand) or - * persistently (values and fields pre-generated in anticipation of - * reuse in from a cache). - *

- * - */ -public interface HttpContent -{ - HttpField getContentType(); - String getContentTypeValue(); - String getCharacterEncoding(); - Type getMimeType(); - - HttpField getContentEncoding(); - String getContentEncodingValue(); - - HttpField getContentLength(); - long getContentLengthValue(); - - HttpField getLastModified(); - String getLastModifiedValue(); - - HttpField getETag(); - String getETagValue(); - - ByteBuffer getIndirectBuffer(); - ByteBuffer getDirectBuffer(); - Resource getResource(); - InputStream getInputStream() throws IOException; - ReadableByteChannel getReadableByteChannel() throws IOException; - void release(); - - HttpContent getGzipContent(); - - - public interface Factory - { - /** - * @param path The path within the context to the resource - * @param maxBuffer The maximum buffer to allocated for this request. For cached content, a larger buffer may have - * previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls. - * @return A {@link HttpContent} - * @throws IOException - */ - HttpContent getContent(String path,int maxBuffer) throws IOException; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCookie.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCookie.java deleted file mode 100644 index 2d769df6ff6..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpCookie.java +++ /dev/null @@ -1,164 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.concurrent.TimeUnit; - -public class HttpCookie -{ - private final String _name; - private final String _value; - private final String _comment; - private final String _domain; - private final long _maxAge; - private final String _path; - private final boolean _secure; - private final int _version; - private final boolean _httpOnly; - private final long _expiration; - - public HttpCookie(String name, String value) - { - this(name, value, -1); - } - - public HttpCookie(String name, String value, String domain, String path) - { - this(name, value, domain, path, -1, false, false); - } - - public HttpCookie(String name, String value, long maxAge) - { - this(name, value, null, null, maxAge, false, false); - } - - public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure) - { - this(name, value, domain, path, maxAge, httpOnly, secure, null, 0); - } - - public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version) - { - _name = name; - _value = value; - _domain = domain; - _path = path; - _maxAge = maxAge; - _httpOnly = httpOnly; - _secure = secure; - _comment = comment; - _version = version; - _expiration = maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(maxAge); - } - - /** - * @return the cookie name - */ - public String getName() - { - return _name; - } - - /** - * @return the cookie value - */ - public String getValue() - { - return _value; - } - - /** - * @return the cookie comment - */ - public String getComment() - { - return _comment; - } - - /** - * @return the cookie domain - */ - public String getDomain() - { - return _domain; - } - - /** - * @return the cookie max age in seconds - */ - public long getMaxAge() - { - return _maxAge; - } - - /** - * @return the cookie path - */ - public String getPath() - { - return _path; - } - - /** - * @return whether the cookie is valid for secure domains - */ - public boolean isSecure() - { - return _secure; - } - - /** - * @return the cookie version - */ - public int getVersion() - { - return _version; - } - - /** - * @return whether the cookie is valid for the http protocol only - */ - public boolean isHttpOnly() - { - return _httpOnly; - } - - /** - * @param timeNanos the time to check for cookie expiration, in nanoseconds - * @return whether the cookie is expired by the given time - */ - public boolean isExpired(long timeNanos) - { - return _expiration >= 0 && timeNanos >= _expiration; - } - - /** - * @return a string representation of this cookie - */ - public String asString() - { - StringBuilder builder = new StringBuilder(); - builder.append(getName()).append("=").append(getValue()); - if (getDomain() != null) - builder.append(";$Domain=").append(getDomain()); - if (getPath() != null) - builder.append(";$Path=").append(getPath()); - return builder.toString(); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpField.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpField.java deleted file mode 100644 index 584ed74269d..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpField.java +++ /dev/null @@ -1,510 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.ArrayList; -import java.util.Objects; - -import org.eclipse.jetty.util.StringUtil; - -/** A HTTP Field - */ -public class HttpField -{ - private final static String __zeroquality="q=0"; - private final HttpHeader _header; - private final String _name; - private final String _value; - // cached hashcode for case insensitive name - private int hash = 0; - - public HttpField(HttpHeader header, String name, String value) - { - _header = header; - _name = name; - _value = value; - } - - public HttpField(HttpHeader header, String value) - { - this(header,header.asString(),value); - } - - public HttpField(HttpHeader header, HttpHeaderValue value) - { - this(header,header.asString(),value.asString()); - } - - public HttpField(String name, String value) - { - this(HttpHeader.CACHE.get(name),name,value); - } - - public HttpHeader getHeader() - { - return _header; - } - - public String getName() - { - return _name; - } - - public String getValue() - { - return _value; - } - - public int getIntValue() - { - return Integer.valueOf(_value); - } - - public long getLongValue() - { - return Long.valueOf(_value); - } - - public String[] getValues() - { - ArrayList list = new ArrayList<>(); - int state = 0; - int start=0; - int end=0; - StringBuilder builder = new StringBuilder(); - - for (int i=0;i<_value.length();i++) - { - char c = _value.charAt(i); - switch(state) - { - case 0: // initial white space - switch(c) - { - case '"': // open quote - state=2; - break; - - case ',': // ignore leading empty field - break; - - case ' ': // more white space - case '\t': - break; - - default: // character - start=i; - end=i; - state=1; - } - break; - - case 1: // In token - switch(c) - { - case ',': // next field - list.add(_value.substring(start,end+1)); - state=0; - break; - - case ' ': // more white space - case '\t': - break; - - default: - end=i; - } - break; - - case 2: // In Quoted - switch(c) - { - case '\\': // next field - state=3; - break; - - case '"': // end quote - list.add(builder.toString()); - builder.setLength(0); - state=4; - break; - - default: - builder.append(c); - } - break; - - case 3: // In Quoted Quoted - builder.append(c); - state=2; - break; - - case 4: // WS after end quote - switch(c) - { - case ' ': // white space - case '\t': // white space - break; - - case ',': // white space - state=0; - break; - - default: - throw new IllegalArgumentException("c="+(int)c); - - } - break; - } - } - - switch(state) - { - case 0: - break; - case 1: - list.add(_value.substring(start,end+1)); - break; - case 4: - break; - - default: - throw new IllegalArgumentException("state="+state); - } - - return list.toArray(new String[list.size()]); - } - - /* ------------------------------------------------------------ */ - /** Look for a value in a possible multi valued field - * @param search Values to search for (case insensitive) - * @return True iff the value is contained in the field value entirely or - * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored, - * except if they are q=0, in which case the item itself is ignored. - */ - public boolean contains(String search) - { - if (search==null) - return _value==null; - if (search.length()==0) - return false; - if (_value==null) - return false; - - search = StringUtil.asciiToLowerCase(search); - - int state=0; - int match=0; - int param=0; - - for (int i=0;i<_value.length();i++) - { - char c = _value.charAt(i); - switch(state) - { - case 0: // initial white space - switch(c) - { - case '"': // open quote - match=0; - state=2; - break; - - case ',': // ignore leading empty field - break; - - case ';': // ignore leading empty field parameter - param=-1; - match=-1; - state=5; - break; - - case ' ': // more white space - case '\t': - break; - - default: // character - match = Character.toLowerCase(c)==search.charAt(0)?1:-1; - state=1; - break; - } - break; - - case 1: // In token - switch(c) - { - case ',': // next field - // Have we matched the token? - if (match==search.length()) - return true; - state=0; - break; - - case ';': - param=match>=0?0:-1; - state=5; // parameter - break; - - default: - if (match>0) - { - if (match=0) - { - if (match=0) - { - if (match=0) - { - if (param<__zeroquality.length()) - param=Character.toLowerCase(c)==__zeroquality.charAt(param)?(param+1):-1; - else if (c!='0'&&c!='.') - param=-1; - } - - } - break; - - default: - throw new IllegalStateException(); - } - } - - return param!=__zeroquality.length() && match==search.length(); - } - - - @Override - public String toString() - { - String v=getValue(); - return getName() + ": " + (v==null?"":v); - } - - public boolean isSameName(HttpField field) - { - if (field==null) - return false; - if (field==this) - return true; - if (_header!=null && _header==field.getHeader()) - return true; - if (_name.equalsIgnoreCase(field.getName())) - return true; - return false; - } - - private int nameHashCode() - { - int h = this.hash; - int len = _name.length(); - if (h == 0 && len > 0) - { - for (int i = 0; i < len; i++) - { - // simple case insensitive hash - char c = _name.charAt(i); - // assuming us-ascii (per last paragraph on http://tools.ietf.org/html/rfc7230#section-3.2.4) - if ((c >= 'a' && c <= 'z')) - c -= 0x20; - h = 31 * h + c; - } - this.hash = h; - } - return h; - } - - @Override - public int hashCode() - { - if (_header==null) - return _value.hashCode() ^ nameHashCode(); - return _value.hashCode() ^ _header.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (o==this) - return true; - if (!(o instanceof HttpField)) - return false; - HttpField field=(HttpField)o; - if (_header!=field.getHeader()) - return false; - if (!_name.equalsIgnoreCase(field.getName())) - return false; - if (_value==null && field.getValue()!=null) - return false; - return Objects.equals(_value,field.getValue()); - } - - public static class IntValueHttpField extends HttpField - { - private final int _int; - - public IntValueHttpField(HttpHeader header, String name, String value, int intValue) - { - super(header,name,value); - _int=intValue; - } - - public IntValueHttpField(HttpHeader header, String name, String value) - { - this(header,name,value,Integer.valueOf(value)); - } - - public IntValueHttpField(HttpHeader header, String name, int intValue) - { - this(header,name,Integer.toString(intValue),intValue); - } - - public IntValueHttpField(HttpHeader header, int value) - { - this(header,header.asString(),value); - } - - @Override - public int getIntValue() - { - return _int; - } - - @Override - public long getLongValue() - { - return _int; - } - } - - public static class LongValueHttpField extends HttpField - { - private final long _long; - - public LongValueHttpField(HttpHeader header, String name, String value, long longValue) - { - super(header,name,value); - _long=longValue; - } - - public LongValueHttpField(HttpHeader header, String name, String value) - { - this(header,name,value,Long.valueOf(value)); - } - - public LongValueHttpField(HttpHeader header, String name, long value) - { - this(header,name,Long.toString(value),value); - } - - public LongValueHttpField(HttpHeader header,long value) - { - this(header,header.asString(),value); - } - - @Override - public int getIntValue() - { - return (int)_long; - } - - @Override - public long getLongValue() - { - return _long; - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFieldPreEncoder.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFieldPreEncoder.java deleted file mode 100644 index 0b1e4d47af3..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFieldPreEncoder.java +++ /dev/null @@ -1,36 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http; - - -/* ------------------------------------------------------------ */ -/** Interface to pre-encode HttpFields. Used by {@link PreEncodedHttpField} - */ -public interface HttpFieldPreEncoder -{ - /* ------------------------------------------------------------ */ - /** The major version this encoder is for. Both HTTP/1.0 and HTTP/1.1 - * use the same field encoding, so the {@link HttpVersion#HTTP_1_0} should - * be return for all HTTP/1.x encodings. - * @return The major version this encoder is for. - */ - HttpVersion getHttpVersion(); - byte[] getEncodedField(HttpHeader header, String headerString, String value); -} \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFields.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFields.java deleted file mode 100644 index 0951a6de515..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpFields.java +++ /dev/null @@ -1,970 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.StringTokenizer; - -import org.eclipse.jetty.util.ArrayTernaryTrie; -import org.eclipse.jetty.util.QuotedStringTokenizer; -import org.eclipse.jetty.util.Trie; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/** - * HTTP Fields. A collection of HTTP header and or Trailer fields. - * - *

This class is not synchronized as it is expected that modifications will only be performed by a - * single thread. - * - *

The cookie handling provided by this class is guided by the Servlet specification and RFC6265. - * - */ -public class HttpFields implements Iterable -{ - @Deprecated - public static final String __separators = ", \t"; - - private static final Logger LOG = Log.getLogger(HttpFields.class); - - private HttpField[] _fields; - private int _size; - - /** - * Initialize an empty HttpFields. - */ - public HttpFields() - { - _fields=new HttpField[20]; - } - - /** - * Initialize an empty HttpFields. - * - * @param capacity the capacity of the http fields - */ - public HttpFields(int capacity) - { - _fields=new HttpField[capacity]; - } - - /** - * Initialize HttpFields from copy. - * - * @param fields the fields to copy data from - */ - public HttpFields(HttpFields fields) - { - _fields=Arrays.copyOf(fields._fields,fields._fields.length+10); - _size=fields._size; - } - - public int size() - { - return _size; - } - - @Override - public Iterator iterator() - { - return new Itr(); - } - - /** - * Get Collection of header names. - * @return the unique set of field names. - */ - public Set getFieldNamesCollection() - { - final Set set = new HashSet<>(_size); - for (HttpField f : this) - { - if (f!=null) - set.add(f.getName()); - } - return set; - } - - /** - * Get enumeration of header _names. Returns an enumeration of strings representing the header - * _names for this request. - * @return an enumeration of field names - */ - public Enumeration getFieldNames() - { - return Collections.enumeration(getFieldNamesCollection()); - } - - /** - * Get a Field by index. - * @param index the field index - * @return A Field value or null if the Field value has not been set - */ - public HttpField getField(int index) - { - if (index>=_size) - throw new NoSuchElementException(); - return _fields[index]; - } - - public HttpField getField(HttpHeader header) - { - for (int i=0;i<_size;i++) - { - HttpField f=_fields[i]; - if (f.getHeader()==header) - return f; - } - return null; - } - - public HttpField getField(String name) - { - for (int i=0;i<_size;i++) - { - HttpField f=_fields[i]; - if (f.getName().equalsIgnoreCase(name)) - return f; - } - return null; - } - - public boolean contains(HttpField field) - { - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.isSameName(field) && f.contains(field.getValue())) - return true; - } - return false; - } - - public boolean contains(HttpHeader header, String value) - { - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getHeader()==header && f.contains(value)) - return true; - } - return false; - } - - public boolean contains(String name, String value) - { - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getName().equalsIgnoreCase(name) && f.contains(value)) - return true; - } - return false; - } - - public boolean contains(HttpHeader header) - { - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getHeader()==header) - return true; - } - return false; - } - - public boolean containsKey(String name) - { - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getName().equalsIgnoreCase(name)) - return true; - } - return false; - } - - @Deprecated - public String getStringField(HttpHeader header) - { - return get(header); - } - - public String get(HttpHeader header) - { - for (int i=0;i<_size;i++) - { - HttpField f=_fields[i]; - if (f.getHeader()==header) - return f.getValue(); - } - return null; - } - - @Deprecated - public String getStringField(String name) - { - return get(name); - } - - public String get(String header) - { - for (int i=0;i<_size;i++) - { - HttpField f=_fields[i]; - if (f.getName().equalsIgnoreCase(header)) - return f.getValue(); - } - return null; - } - - /** - * Get multiple header of the same name - * - * @return List the values - * @param header the header - */ - public List getValuesList(HttpHeader header) - { - final List list = new ArrayList<>(); - for (HttpField f : this) - if (f.getHeader()==header) - list.add(f.getValue()); - return list; - } - - /** - * Get multiple header of the same name - * - * @return List the header values - * @param name the case-insensitive field name - */ - public List getValuesList(String name) - { - final List list = new ArrayList<>(); - for (HttpField f : this) - if (f.getName().equalsIgnoreCase(name)) - list.add(f.getValue()); - return list; - } - - /** - * Get multiple field values of the same name, split - * as a {@link QuotedCSV} - * - * @return List the values with OWS stripped - * @param header The header - * @param keepQuotes True if the fields are kept quoted - */ - public List getCSV(HttpHeader header,boolean keepQuotes) - { - QuotedCSV values = new QuotedCSV(keepQuotes); - for (HttpField f : this) - if (f.getHeader()==header) - values.addValue(f.getValue()); - return values.getValues(); - } - - /** - * Get multiple field values of the same name - * as a {@link QuotedCSV} - * - * @return List the values with OWS stripped - * @param name the case-insensitive field name - * @param keepQuotes True if the fields are kept quoted - */ - public List getCSV(String name,boolean keepQuotes) - { - QuotedCSV values = new QuotedCSV(keepQuotes); - for (HttpField f : this) - if (f.getName().equalsIgnoreCase(name)) - values.addValue(f.getValue()); - return values.getValues(); - } - - /** - * Get multiple field values of the same name, split and - * sorted as a {@link QuotedQualityCSV} - * - * @return List the values in quality order with the q param and OWS stripped - * @param header The header - */ - public List getQualityCSV(HttpHeader header) - { - QuotedQualityCSV values = new QuotedQualityCSV(); - for (HttpField f : this) - if (f.getHeader()==header) - values.addValue(f.getValue()); - return values.getValues(); - } - - /** - * Get multiple field values of the same name, split and - * sorted as a {@link QuotedQualityCSV} - * - * @return List the values in quality order with the q param and OWS stripped - * @param name the case-insensitive field name - */ - public List getQualityCSV(String name) - { - QuotedQualityCSV values = new QuotedQualityCSV(); - for (HttpField f : this) - if (f.getName().equalsIgnoreCase(name)) - values.addValue(f.getValue()); - return values.getValues(); - } - - /** - * Get multi headers - * - * @return Enumeration of the values - * @param name the case-insensitive field name - */ - public Enumeration getValues(final String name) - { - for (int i=0;i<_size;i++) - { - final HttpField f = _fields[i]; - - if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null) - { - final int first=i; - return new Enumeration() - { - HttpField field=f; - int i = first+1; - - @Override - public boolean hasMoreElements() - { - if (field==null) - { - while (i<_size) - { - field=_fields[i++]; - if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null) - return true; - } - field=null; - return false; - } - return true; - } - - @Override - public String nextElement() throws NoSuchElementException - { - if (hasMoreElements()) - { - String value=field.getValue(); - field=null; - return value; - } - throw new NoSuchElementException(); - } - }; - } - } - - List empty=Collections.emptyList(); - return Collections.enumeration(empty); - } - - /** - * Get multi field values with separator. The multiple values can be represented as separate - * headers of the same name, or by a single header using the separator(s), or a combination of - * both. Separators may be quoted. - * - * @param name the case-insensitive field name - * @param separators String of separators. - * @return Enumeration of the values, or null if no such header. - */ - @Deprecated - public Enumeration getValues(String name, final String separators) - { - final Enumeration e = getValues(name); - if (e == null) - return null; - return new Enumeration() - { - QuotedStringTokenizer tok = null; - - @Override - public boolean hasMoreElements() - { - if (tok != null && tok.hasMoreElements()) return true; - while (e.hasMoreElements()) - { - String value = e.nextElement(); - if (value!=null) - { - tok = new QuotedStringTokenizer(value, separators, false, false); - if (tok.hasMoreElements()) return true; - } - } - tok = null; - return false; - } - - @Override - public String nextElement() throws NoSuchElementException - { - if (!hasMoreElements()) throw new NoSuchElementException(); - String next = (String) tok.nextElement(); - if (next != null) next = next.trim(); - return next; - } - }; - } - - public void put(HttpField field) - { - boolean put=false; - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.isSameName(field)) - { - if (put) - { - System.arraycopy(_fields,i+1,_fields,i,--_size-i); - } - else - { - _fields[i]=field; - put=true; - } - } - } - if (!put) - add(field); - } - - /** - * Set a field. - * - * @param name the name of the field - * @param value the value of the field. If null the field is cleared. - */ - public void put(String name, String value) - { - if (value == null) - remove(name); - else - put(new HttpField(name, value)); - } - - public void put(HttpHeader header, HttpHeaderValue value) - { - put(header,value.toString()); - } - - /** - * Set a field. - * - * @param header the header name of the field - * @param value the value of the field. If null the field is cleared. - */ - public void put(HttpHeader header, String value) - { - if (value == null) - remove(header); - else - put(new HttpField(header, value)); - } - - /** - * Set a field. - * - * @param name the name of the field - * @param list the List value of the field. If null the field is cleared. - */ - public void put(String name, List list) - { - remove(name); - for (String v : list) - if (v!=null) - add(name,v); - } - - /** - * Add to or set a field. If the field is allowed to have multiple values, add will add multiple - * headers of the same name. - * - * @param name the name of the field - * @param value the value of the field. - */ - public void add(String name, String value) - { - if (value == null) - return; - - HttpField field = new HttpField(name, value); - add(field); - } - - public void add(HttpHeader header, HttpHeaderValue value) - { - add(header,value.toString()); - } - - /** - * Add to or set a field. If the field is allowed to have multiple values, add will add multiple - * headers of the same name. - * - * @param header the header - * @param value the value of the field. - */ - public void add(HttpHeader header, String value) - { - if (value == null) throw new IllegalArgumentException("null value"); - - HttpField field = new HttpField(header, value); - add(field); - } - - /** - * Remove a field. - * - * @param name the field to remove - * @return the header that was removed - */ - public HttpField remove(HttpHeader name) - { - HttpField removed=null; - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getHeader()==name) - { - removed=f; - System.arraycopy(_fields,i+1,_fields,i,--_size-i); - } - } - return removed; - } - - /** - * Remove a field. - * - * @param name the field to remove - * @return the header that was removed - */ - public HttpField remove(String name) - { - HttpField removed=null; - for (int i=_size;i-->0;) - { - HttpField f=_fields[i]; - if (f.getName().equalsIgnoreCase(name)) - { - removed=f; - System.arraycopy(_fields,i+1,_fields,i,--_size-i); - } - } - return removed; - } - - /** - * Get a header as an long value. Returns the value of an integer field or -1 if not found. The - * case of the field name is ignored. - * - * @param name the case-insensitive field name - * @return the value of the field as a long - * @exception NumberFormatException If bad long found - */ - public long getLongField(String name) throws NumberFormatException - { - HttpField field = getField(name); - return field==null?-1L:field.getLongValue(); - } - - /** - * Get a header as a date value. Returns the value of a date field, or -1 if not found. The case - * of the field name is ignored. - * - * @param name the case-insensitive field name - * @return the value of the field as a number of milliseconds since unix epoch - */ - public long getDateField(String name) - { - HttpField field = getField(name); - if (field == null) - return -1; - - String val = valueParameters(field.getValue(), null); - if (val == null) - return -1; - - final long date = DateParser.parseDate(val); - if (date==-1) - throw new IllegalArgumentException("Cannot convert date: " + val); - return date; - } - - - /** - * Sets the value of an long field. - * - * @param name the field name - * @param value the field long value - */ - public void putLongField(HttpHeader name, long value) - { - String v = Long.toString(value); - put(name, v); - } - - /** - * Sets the value of an long field. - * - * @param name the field name - * @param value the field long value - */ - public void putLongField(String name, long value) - { - String v = Long.toString(value); - put(name, v); - } - - - /** - * Sets the value of a date field. - * - * @param name the field name - * @param date the field date value - */ - public void putDateField(HttpHeader name, long date) - { - String d=DateGenerator.formatDate(date); - put(name, d); - } - - /** - * Sets the value of a date field. - * - * @param name the field name - * @param date the field date value - */ - public void putDateField(String name, long date) - { - String d=DateGenerator.formatDate(date); - put(name, d); - } - - /** - * Sets the value of a date field. - * - * @param name the field name - * @param date the field date value - */ - public void addDateField(String name, long date) - { - String d=DateGenerator.formatDate(date); - add(name,d); - } - - @Override - public int hashCode() - { - int hash=0; - for (HttpField field:_fields) - hash+=field.hashCode(); - return hash; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof HttpFields)) - return false; - - HttpFields that = (HttpFields)o; - - // Order is not important, so we cannot rely on List.equals(). - if (size() != that.size()) - return false; - - loop: for (HttpField fi : this) - { - for (HttpField fa : that) - { - if (fi.equals(fa)) - continue loop; - } - return false; - } - return true; - } - - @Override - public String toString() - { - try - { - StringBuilder buffer = new StringBuilder(); - for (HttpField field : this) - { - if (field != null) - { - String tmp = field.getName(); - if (tmp != null) buffer.append(tmp); - buffer.append(": "); - tmp = field.getValue(); - if (tmp != null) buffer.append(tmp); - buffer.append("\r\n"); - } - } - buffer.append("\r\n"); - return buffer.toString(); - } - catch (Exception e) - { - LOG.warn(e); - return e.toString(); - } - } - - public void clear() - { - _size=0; - } - - public void add(HttpField field) - { - if (field!=null) - { - if (_size==_fields.length) - _fields=Arrays.copyOf(_fields,_size*2); - _fields[_size++]=field; - } - } - - public void addAll(HttpFields fields) - { - for (int i=0;i e = fields.getFieldNames(); - while (e.hasMoreElements()) - { - String name = e.nextElement(); - Enumeration values = fields.getValues(name); - while (values.hasMoreElements()) - add(name, values.nextElement()); - } - } - - /** - * Get field value without parameters. Some field values can have parameters. This method separates the - * value from the parameters and optionally populates a map with the parameters. For example: - * - *

-     *
-     * FieldName : Value ; param1=val1 ; param2=val2
-     *
-     * 
- * - * @param value The Field value, possibly with parameters. - * @return The value. - */ - public static String stripParameters(String value) - { - if (value == null) return null; - - int i = value.indexOf(';'); - if (i < 0) return value; - return value.substring(0, i).trim(); - } - - /** - * Get field value parameters. Some field values can have parameters. This method separates the - * value from the parameters and optionally populates a map with the parameters. For example: - * - *
-     *
-     * FieldName : Value ; param1=val1 ; param2=val2
-     *
-     * 
- * - * @param value The Field value, possibly with parameters. - * @param parameters A map to populate with the parameters, or null - * @return The value. - */ - public static String valueParameters(String value, Map parameters) - { - if (value == null) return null; - - int i = value.indexOf(';'); - if (i < 0) return value; - if (parameters == null) return value.substring(0, i).trim(); - - StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true); - while (tok1.hasMoreTokens()) - { - String token = tok1.nextToken(); - StringTokenizer tok2 = new QuotedStringTokenizer(token, "= "); - if (tok2.hasMoreTokens()) - { - String paramName = tok2.nextToken(); - String paramVal = null; - if (tok2.hasMoreTokens()) paramVal = tok2.nextToken(); - parameters.put(paramName, paramVal); - } - } - - return value.substring(0, i).trim(); - } - - @Deprecated - private static final Float __one = new Float("1.0"); - @Deprecated - private static final Float __zero = new Float("0.0"); - @Deprecated - private static final Trie __qualities = new ArrayTernaryTrie<>(); - static - { - __qualities.put("*", __one); - __qualities.put("1.0", __one); - __qualities.put("1", __one); - __qualities.put("0.9", new Float("0.9")); - __qualities.put("0.8", new Float("0.8")); - __qualities.put("0.7", new Float("0.7")); - __qualities.put("0.66", new Float("0.66")); - __qualities.put("0.6", new Float("0.6")); - __qualities.put("0.5", new Float("0.5")); - __qualities.put("0.4", new Float("0.4")); - __qualities.put("0.33", new Float("0.33")); - __qualities.put("0.3", new Float("0.3")); - __qualities.put("0.2", new Float("0.2")); - __qualities.put("0.1", new Float("0.1")); - __qualities.put("0", __zero); - __qualities.put("0.0", __zero); - } - - @Deprecated - public static Float getQuality(String value) - { - if (value == null) return __zero; - - int qe = value.indexOf(";"); - if (qe++ < 0 || qe == value.length()) return __one; - - if (value.charAt(qe++) == 'q') - { - qe++; - Float q = __qualities.get(value, qe, value.length() - qe); - if (q != null) - return q; - } - - Map params = new HashMap<>(4); - valueParameters(value, params); - String qs = params.get("q"); - if (qs==null) - qs="*"; - Float q = __qualities.get(qs); - if (q == null) - { - try - { - q = new Float(qs); - } - catch (Exception e) - { - q = __one; - } - } - return q; - } - - /** - * List values in quality order. - * - * @param e Enumeration of values with quality parameters - * @return values in quality order. - */ - @Deprecated - public static List qualityList(Enumeration e) - { - if (e == null || !e.hasMoreElements()) - return Collections.emptyList(); - - QuotedQualityCSV values = new QuotedQualityCSV(); - while(e.hasMoreElements()) - values.addValue(e.nextElement()); - return values.getValues(); - } - - - private class Itr implements Iterator - { - int _cursor; // index of next element to return - int _last=-1; - - public boolean hasNext() - { - return _cursor != _size; - } - - public HttpField next() - { - int i = _cursor; - if (i >= _size) - throw new NoSuchElementException(); - _cursor = i + 1; - return _fields[_last=i]; - } - - public void remove() - { - if (_last<0) - throw new IllegalStateException(); - - System.arraycopy(_fields,_last+1,_fields,_last,--_size-_last); - _cursor=_last; - _last=-1; - } - } - -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpGenerator.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpGenerator.java deleted file mode 100644 index f743379eb4b..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpGenerator.java +++ /dev/null @@ -1,1023 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.http.HttpTokens.EndOfContent; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * HttpGenerator. Builds HTTP Messages. - *

- * If the system property "org.eclipse.jetty.http.HttpGenerator.STRICT" is set to true, - * then the generator will strictly pass on the exact strings received from methods and header - * fields. Otherwise a fast case insensitive string lookup is used that may alter the - * case and white space of some methods/headers - */ -public class HttpGenerator -{ - private final static Logger LOG = Log.getLogger(HttpGenerator.class); - - public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT"); - - private final static byte[] __colon_space = new byte[] {':',' '}; - private final static HttpHeaderValue[] CLOSE = {HttpHeaderValue.CLOSE}; - public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,100,null,null,-1); - public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,102,null,null,-1); - public final static MetaData.Response RESPONSE_500_INFO = - new MetaData.Response(HttpVersion.HTTP_1_1,HttpStatus.INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0); - - // states - public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END } - public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,FLUSH,CONTINUE,SHUTDOWN_OUT,DONE} - - // other statics - public static final int CHUNK_SIZE = 12; - - private State _state = State.START; - private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT; - - private long _contentPrepared = 0; - private boolean _noContent = false; - private Boolean _persistent = null; - - private final int _send; - private final static int SEND_SERVER = 0x01; - private final static int SEND_XPOWEREDBY = 0x02; - private final static Set __assumedContentMethods = new HashSet<>(Arrays.asList(new String[]{HttpMethod.POST.asString(),HttpMethod.PUT.asString()})); - - /* ------------------------------------------------------------------------------- */ - public static void setJettyVersion(String serverVersion) - { - SEND[SEND_SERVER] = StringUtil.getBytes("Server: " + serverVersion + "\015\012"); - SEND[SEND_XPOWEREDBY] = StringUtil.getBytes("X-Powered-By: " + serverVersion + "\015\012"); - SEND[SEND_SERVER | SEND_XPOWEREDBY] = StringUtil.getBytes("Server: " + serverVersion + "\015\012X-Powered-By: " + - serverVersion + "\015\012"); - } - - /* ------------------------------------------------------------------------------- */ - // data - private boolean _needCRLF = false; - - /* ------------------------------------------------------------------------------- */ - public HttpGenerator() - { - this(false,false); - } - - /* ------------------------------------------------------------------------------- */ - public HttpGenerator(boolean sendServerVersion,boolean sendXPoweredBy) - { - _send=(sendServerVersion?SEND_SERVER:0) | (sendXPoweredBy?SEND_XPOWEREDBY:0); - } - - /* ------------------------------------------------------------------------------- */ - public void reset() - { - _state = State.START; - _endOfContent = EndOfContent.UNKNOWN_CONTENT; - _noContent=false; - _persistent = null; - _contentPrepared = 0; - _needCRLF = false; - } - - /* ------------------------------------------------------------ */ - @Deprecated - public boolean getSendServerVersion () - { - return (_send&SEND_SERVER)!=0; - } - - /* ------------------------------------------------------------ */ - @Deprecated - public void setSendServerVersion (boolean sendServerVersion) - { - throw new UnsupportedOperationException(); - } - - /* ------------------------------------------------------------ */ - public State getState() - { - return _state; - } - - /* ------------------------------------------------------------ */ - public boolean isState(State state) - { - return _state == state; - } - - /* ------------------------------------------------------------ */ - public boolean isIdle() - { - return _state == State.START; - } - - /* ------------------------------------------------------------ */ - public boolean isEnd() - { - return _state == State.END; - } - - /* ------------------------------------------------------------ */ - public boolean isCommitted() - { - return _state.ordinal() >= State.COMMITTED.ordinal(); - } - - /* ------------------------------------------------------------ */ - public boolean isChunking() - { - return _endOfContent==EndOfContent.CHUNKED_CONTENT; - } - - /* ------------------------------------------------------------ */ - public boolean isNoContent() - { - return _noContent; - } - - /* ------------------------------------------------------------ */ - public void setPersistent(boolean persistent) - { - _persistent=persistent; - } - - /* ------------------------------------------------------------ */ - /** - * @return true if known to be persistent - */ - public boolean isPersistent() - { - return Boolean.TRUE.equals(_persistent); - } - - /* ------------------------------------------------------------ */ - public boolean isWritten() - { - return _contentPrepared>0; - } - - /* ------------------------------------------------------------ */ - public long getContentPrepared() - { - return _contentPrepared; - } - - /* ------------------------------------------------------------ */ - public void abort() - { - _persistent=false; - _state=State.END; - _endOfContent=null; - } - - /* ------------------------------------------------------------ */ - public Result generateRequest(MetaData.Request info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException - { - switch(_state) - { - case START: - { - if (info==null) - return Result.NEED_INFO; - - if (header==null) - return Result.NEED_HEADER; - - // If we have not been told our persistence, set the default - if (_persistent==null) - { - _persistent=info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal(); - if (!_persistent && HttpMethod.CONNECT.is(info.getMethod())) - _persistent=true; - } - - // prepare the header - int pos=BufferUtil.flipToFill(header); - try - { - // generate ResponseLine - generateRequestLine(info,header); - - if (info.getVersion()==HttpVersion.HTTP_0_9) - throw new BadMessageException(500,"HTTP/0.9 not supported"); - - generateHeaders(info,header,content,last); - - boolean expect100 = info.getFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); - - if (expect100) - { - _state = State.COMMITTED; - } - else - { - // handle the content. - int len = BufferUtil.length(content); - if (len>0) - { - _contentPrepared+=len; - if (isChunking()) - prepareChunk(header,len); - } - _state = last?State.COMPLETING:State.COMMITTED; - } - - return Result.FLUSH; - } - catch(Exception e) - { - String message= (e instanceof BufferOverflowException)?"Request header too large":e.getMessage(); - throw new BadMessageException(500,message,e); - } - finally - { - BufferUtil.flipToFlush(header,pos); - } - } - - case COMMITTED: - { - int len = BufferUtil.length(content); - - if (len>0) - { - // Do we need a chunk buffer? - if (isChunking()) - { - // Do we need a chunk buffer? - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,len); - BufferUtil.flipToFlush(chunk,0); - } - _contentPrepared+=len; - } - - if (last) - _state=State.COMPLETING; - - return len>0?Result.FLUSH:Result.CONTINUE; - } - - case COMPLETING: - { - if (BufferUtil.hasContent(content)) - { - if (LOG.isDebugEnabled()) - LOG.debug("discarding content in COMPLETING"); - BufferUtil.clear(content); - } - - if (isChunking()) - { - // Do we need a chunk buffer? - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,0); - BufferUtil.flipToFlush(chunk,0); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - return Result.FLUSH; - } - - _state=State.END; - return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT; - } - - case END: - if (BufferUtil.hasContent(content)) - { - if (LOG.isDebugEnabled()) - LOG.debug("discarding content in COMPLETING"); - BufferUtil.clear(content); - } - return Result.DONE; - - default: - throw new IllegalStateException(); - } - } - - /* ------------------------------------------------------------ */ - public Result generateResponse(MetaData.Response info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException - { - return generateResponse(info,false,header,chunk,content,last); - } - - /* ------------------------------------------------------------ */ - public Result generateResponse(MetaData.Response info, boolean head, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException - { - switch(_state) - { - case START: - { - if (info==null) - return Result.NEED_INFO; - HttpVersion version=info.getVersion(); - if (version==null) - throw new BadMessageException(500,"No version"); - switch(version) - { - case HTTP_1_0: - if (_persistent==null) - _persistent=Boolean.FALSE; - break; - - case HTTP_1_1: - if (_persistent==null) - _persistent=Boolean.TRUE; - break; - - default: - _persistent = false; - _endOfContent=EndOfContent.EOF_CONTENT; - if (BufferUtil.hasContent(content)) - _contentPrepared+=content.remaining(); - _state = last?State.COMPLETING:State.COMMITTED; - return Result.FLUSH; - } - - // Do we need a response header - if (header==null) - return Result.NEED_HEADER; - - // prepare the header - int pos=BufferUtil.flipToFill(header); - try - { - // generate ResponseLine - generateResponseLine(info,header); - - // Handle 1xx and no content responses - int status=info.getStatus(); - if (status>=100 && status<200 ) - { - _noContent=true; - - if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 ) - { - header.put(HttpTokens.CRLF); - _state=State.COMPLETING_1XX; - return Result.FLUSH; - } - } - else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304) - { - _noContent=true; - } - - generateHeaders(info,header,content,last); - - // handle the content. - int len = BufferUtil.length(content); - if (len>0) - { - _contentPrepared+=len; - if (isChunking() && !head) - prepareChunk(header,len); - } - _state = last?State.COMPLETING:State.COMMITTED; - } - catch(Exception e) - { - String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage(); - throw new BadMessageException(500,message,e); - } - finally - { - BufferUtil.flipToFlush(header,pos); - } - - return Result.FLUSH; - } - - case COMMITTED: - { - int len = BufferUtil.length(content); - - // handle the content. - if (len>0) - { - if (isChunking()) - { - if (chunk==null) - return Result.NEED_CHUNK; - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,len); - BufferUtil.flipToFlush(chunk,0); - } - _contentPrepared+=len; - } - - if (last) - { - _state=State.COMPLETING; - return len>0?Result.FLUSH:Result.CONTINUE; - } - return len>0?Result.FLUSH:Result.DONE; - - } - - case COMPLETING_1XX: - { - reset(); - return Result.DONE; - } - - case COMPLETING: - { - if (BufferUtil.hasContent(content)) - { - if (LOG.isDebugEnabled()) - LOG.debug("discarding content in COMPLETING"); - BufferUtil.clear(content); - } - - if (isChunking()) - { - // Do we need a chunk buffer? - if (chunk==null) - return Result.NEED_CHUNK; - - // Write the last chunk - BufferUtil.clearToFill(chunk); - prepareChunk(chunk,0); - BufferUtil.flipToFlush(chunk,0); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - return Result.FLUSH; - } - - _state=State.END; - - return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT; - } - - case END: - if (BufferUtil.hasContent(content)) - { - if (LOG.isDebugEnabled()) - LOG.debug("discarding content in COMPLETING"); - BufferUtil.clear(content); - } - return Result.DONE; - - default: - throw new IllegalStateException(); - } - } - - /* ------------------------------------------------------------ */ - private void prepareChunk(ByteBuffer chunk, int remaining) - { - // if we need CRLF add this to header - if (_needCRLF) - BufferUtil.putCRLF(chunk); - - // Add the chunk size to the header - if (remaining>0) - { - BufferUtil.putHexInt(chunk, remaining); - BufferUtil.putCRLF(chunk); - _needCRLF=true; - } - else - { - chunk.put(LAST_CHUNK); - _needCRLF=false; - } - } - - /* ------------------------------------------------------------ */ - private void generateRequestLine(MetaData.Request request,ByteBuffer header) - { - header.put(StringUtil.getBytes(request.getMethod())); - header.put((byte)' '); - header.put(StringUtil.getBytes(request.getURIString())); - header.put((byte)' '); - header.put(request.getVersion().toBytes()); - header.put(HttpTokens.CRLF); - } - - /* ------------------------------------------------------------ */ - private void generateResponseLine(MetaData.Response response, ByteBuffer header) - { - // Look for prepared response line - int status=response.getStatus(); - PreparedResponse preprepared = status<__preprepared.length?__preprepared[status]:null; - String reason=response.getReason(); - if (preprepared!=null) - { - if (reason==null) - header.put(preprepared._responseLine); - else - { - header.put(preprepared._schemeCode); - header.put(getReasonBytes(reason)); - header.put(HttpTokens.CRLF); - } - } - else // generate response line - { - header.put(HTTP_1_1_SPACE); - header.put((byte) ('0' + status / 100)); - header.put((byte) ('0' + (status % 100) / 10)); - header.put((byte) ('0' + (status % 10))); - header.put((byte) ' '); - if (reason==null) - { - header.put((byte) ('0' + status / 100)); - header.put((byte) ('0' + (status % 100) / 10)); - header.put((byte) ('0' + (status % 10))); - } - else - header.put(getReasonBytes(reason)); - header.put(HttpTokens.CRLF); - } - } - - /* ------------------------------------------------------------ */ - private byte[] getReasonBytes(String reason) - { - if (reason.length()>1024) - reason=reason.substring(0,1024); - byte[] _bytes = StringUtil.getBytes(reason); - - for (int i=_bytes.length;i-->0;) - if (_bytes[i]=='\r' || _bytes[i]=='\n') - _bytes[i]='?'; - return _bytes; - } - - /* ------------------------------------------------------------ */ - private void generateHeaders(MetaData _info,ByteBuffer header,ByteBuffer content,boolean last) - { - final MetaData.Request request=(_info instanceof MetaData.Request)?(MetaData.Request)_info:null; - final MetaData.Response response=(_info instanceof MetaData.Response)?(MetaData.Response)_info:null; - - // default field values - int send=_send; - HttpField transfer_encoding=null; - boolean keep_alive=false; - boolean close=false; - boolean content_type=false; - StringBuilder connection = null; - long content_length = _info.getContentLength(); - - // Generate fields - HttpFields fields = _info.getFields(); - if (fields != null) - { - int n=fields.size(); - for (int f=0;f0) - { - values=new HttpHeaderValue[split.length]; - for (int i=0;i0) - { - // we have been given a content length - _endOfContent=EndOfContent.CONTENT_LENGTH; - if ((response!=null || content_length>0 || content_type ) && !_noContent) - { - // known length but not actually set. - header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace()); - BufferUtil.putDecLong(header, content_length); - header.put(HttpTokens.CRLF); - } - } - else if (last) - { - // we have seen all the _content there is, so we can be content-length limited. - _endOfContent=EndOfContent.CONTENT_LENGTH; - long actual_length = _contentPrepared+BufferUtil.length(content); - - if (content_length>=0 && content_length!=actual_length) - throw new BadMessageException(500,"Content-Length header("+content_length+") != actual("+actual_length+")"); - - // Do we need to tell the headers about it - putContentLength(header,actual_length,content_type,request,response); - } - else - { - // No idea, so we must assume that a body is coming. - _endOfContent = EndOfContent.CHUNKED_CONTENT; - // HTTP 1.0 does not understand chunked content, so we must use EOF content. - // For a request with HTTP 1.0 & Connection: keep-alive - // we *must* close the connection, otherwise the client - // has no way to detect the end of the content. - if (!isPersistent() || _info.getVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal()) - _endOfContent = EndOfContent.EOF_CONTENT; - } - break; - - case CONTENT_LENGTH: - { - putContentLength(header,content_length,content_type,request,response); - break; - } - - case NO_CONTENT: - throw new BadMessageException(500); - - case EOF_CONTENT: - _persistent = request!=null; - break; - - case CHUNKED_CONTENT: - break; - - default: - break; - } - - // Add transfer_encoding if needed - if (isChunking()) - { - // try to use user supplied encoding as it may have other values. - if (transfer_encoding != null && !HttpHeaderValue.CHUNKED.toString().equalsIgnoreCase(transfer_encoding.getValue())) - { - String c = transfer_encoding.getValue(); - if (c.endsWith(HttpHeaderValue.CHUNKED.toString())) - putTo(transfer_encoding,header); - else - throw new BadMessageException(500,"BAD TE"); - } - else - header.put(TRANSFER_ENCODING_CHUNKED); - } - - // Handle connection if need be - if (_endOfContent==EndOfContent.EOF_CONTENT) - { - keep_alive=false; - _persistent=false; - } - - // If this is a response, work out persistence - if (response!=null) - { - if (!isPersistent() && (close || _info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal())) - { - if (connection==null) - header.put(CONNECTION_CLOSE); - else - { - header.put(CONNECTION_CLOSE,0,CONNECTION_CLOSE.length-2); - header.put((byte)','); - header.put(StringUtil.getBytes(connection.toString())); - header.put(CRLF); - } - } - else if (keep_alive) - { - if (connection==null) - header.put(CONNECTION_KEEP_ALIVE); - else - { - header.put(CONNECTION_KEEP_ALIVE,0,CONNECTION_KEEP_ALIVE.length-2); - header.put((byte)','); - header.put(StringUtil.getBytes(connection.toString())); - header.put(CRLF); - } - } - else if (connection!=null) - { - header.put(HttpHeader.CONNECTION.getBytesColonSpace()); - header.put(StringUtil.getBytes(connection.toString())); - header.put(CRLF); - } - } - - if (status>199) - header.put(SEND[send]); - - // end the header. - header.put(HttpTokens.CRLF); - } - - /* ------------------------------------------------------------------------------- */ - private void putContentLength(ByteBuffer header, long contentLength, boolean contentType, MetaData.Request request, MetaData.Response response) - { - if (contentLength>0) - { - header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace()); - BufferUtil.putDecLong(header, contentLength); - header.put(HttpTokens.CRLF); - } - else if (!_noContent) - { - if (contentType || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod()))) - header.put(CONTENT_LENGTH_0); - } - } - - /* ------------------------------------------------------------------------------- */ - public static byte[] getReasonBuffer(int code) - { - PreparedResponse status = code<__preprepared.length?__preprepared[code]:null; - if (status!=null) - return status._reason; - return null; - } - - /* ------------------------------------------------------------------------------- */ - @Override - public String toString() - { - return String.format("%s@%x{s=%s}", - getClass().getSimpleName(), - hashCode(), - _state); - } - - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - // common _content - private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; - private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012"); - private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012"); - private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012"); - private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" "); - private static final byte[] CRLF = StringUtil.getBytes("\015\012"); - private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012"); - private static final byte[][] SEND = new byte[][]{ - new byte[0], - StringUtil.getBytes("Server: Jetty(9.x.x)\015\012"), - StringUtil.getBytes("X-Powered-By: Jetty(9.x.x)\015\012"), - StringUtil.getBytes("Server: Jetty(9.x.x)\015\012X-Powered-By: Jetty(9.x.x)\015\012") - }; - - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - // Build cache of response lines for status - private static class PreparedResponse - { - byte[] _reason; - byte[] _schemeCode; - byte[] _responseLine; - } - private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE+1]; - static - { - int versionLength=HttpVersion.HTTP_1_1.toString().length(); - - for (int i=0;i<__preprepared.length;i++) - { - HttpStatus.Code code = HttpStatus.getCode(i); - if (code==null) - continue; - String reason=code.getMessage(); - byte[] line=new byte[versionLength+5+reason.length()+2]; - HttpVersion.HTTP_1_1.toBuffer().get(line,0,versionLength); - line[versionLength+0]=' '; - line[versionLength+1]=(byte)('0'+i/100); - line[versionLength+2]=(byte)('0'+(i%100)/10); - line[versionLength+3]=(byte)('0'+(i%10)); - line[versionLength+4]=' '; - for (int j=0;j0xff || c=='\r' || c=='\n'|| c==':') - buffer.put((byte)'?'); - else - buffer.put((byte)(0xff&c)); - } - } - - private static void putSanitisedValue(String s,ByteBuffer buffer) - { - int l=s.length(); - for (int i=0;i0xff || c=='\r' || c=='\n') - buffer.put((byte)' '); - else - buffer.put((byte)(0xff&c)); - } - } - - public static void putTo(HttpField field, ByteBuffer bufferInFillMode) - { - if (field instanceof PreEncodedHttpField) - { - ((PreEncodedHttpField)field).putTo(bufferInFillMode,HttpVersion.HTTP_1_0); - } - else - { - HttpHeader header=field.getHeader(); - if (header!=null) - { - bufferInFillMode.put(header.getBytesColonSpace()); - putSanitisedValue(field.getValue(),bufferInFillMode); - } - else - { - putSanitisedName(field.getName(),bufferInFillMode); - bufferInFillMode.put(__colon_space); - putSanitisedValue(field.getValue(),bufferInFillMode); - } - - BufferUtil.putCRLF(bufferInFillMode); - } - } - - public static void putTo(HttpFields fields, ByteBuffer bufferInFillMode) - { - for (HttpField field : fields) - { - if (field != null) - putTo(field,bufferInFillMode); - } - BufferUtil.putCRLF(bufferInFillMode); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeader.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeader.java deleted file mode 100644 index b57a5fa2447..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeader.java +++ /dev/null @@ -1,191 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.Trie; - - -public enum HttpHeader -{ - /* ------------------------------------------------------------ */ - /** General Fields. - */ - CONNECTION("Connection"), - CACHE_CONTROL("Cache-Control"), - DATE("Date"), - PRAGMA("Pragma"), - PROXY_CONNECTION ("Proxy-Connection"), - TRAILER("Trailer"), - TRANSFER_ENCODING("Transfer-Encoding"), - UPGRADE("Upgrade"), - VIA("Via"), - WARNING("Warning"), - NEGOTIATE("Negotiate"), - - /* ------------------------------------------------------------ */ - /** Entity Fields. - */ - ALLOW("Allow"), - CONTENT_ENCODING("Content-Encoding"), - CONTENT_LANGUAGE("Content-Language"), - CONTENT_LENGTH("Content-Length"), - CONTENT_LOCATION("Content-Location"), - CONTENT_MD5("Content-MD5"), - CONTENT_RANGE("Content-Range"), - CONTENT_TYPE("Content-Type"), - EXPIRES("Expires"), - LAST_MODIFIED("Last-Modified"), - - /* ------------------------------------------------------------ */ - /** Request Fields. - */ - ACCEPT("Accept"), - ACCEPT_CHARSET("Accept-Charset"), - ACCEPT_ENCODING("Accept-Encoding"), - ACCEPT_LANGUAGE("Accept-Language"), - AUTHORIZATION("Authorization"), - EXPECT("Expect"), - FORWARDED("Forwarded"), - FROM("From"), - HOST("Host"), - IF_MATCH("If-Match"), - IF_MODIFIED_SINCE("If-Modified-Since"), - IF_NONE_MATCH("If-None-Match"), - IF_RANGE("If-Range"), - IF_UNMODIFIED_SINCE("If-Unmodified-Since"), - KEEP_ALIVE("Keep-Alive"), - MAX_FORWARDS("Max-Forwards"), - PROXY_AUTHORIZATION("Proxy-Authorization"), - RANGE("Range"), - REQUEST_RANGE("Request-Range"), - REFERER("Referer"), - TE("TE"), - USER_AGENT("User-Agent"), - X_FORWARDED_FOR("X-Forwarded-For"), - X_FORWARDED_PROTO("X-Forwarded-Proto"), - X_FORWARDED_SERVER("X-Forwarded-Server"), - X_FORWARDED_HOST("X-Forwarded-Host"), - - /* ------------------------------------------------------------ */ - /** Response Fields. - */ - ACCEPT_RANGES("Accept-Ranges"), - AGE("Age"), - ETAG("ETag"), - LOCATION("Location"), - PROXY_AUTHENTICATE("Proxy-Authenticate"), - RETRY_AFTER("Retry-After"), - SERVER("Server"), - SERVLET_ENGINE("Servlet-Engine"), - VARY("Vary"), - WWW_AUTHENTICATE("WWW-Authenticate"), - - /* ------------------------------------------------------------ */ - /** Other Fields. - */ - COOKIE("Cookie"), - SET_COOKIE("Set-Cookie"), - SET_COOKIE2("Set-Cookie2"), - MIME_VERSION("MIME-Version"), - IDENTITY("identity"), - - X_POWERED_BY("X-Powered-By"), - HTTP2_SETTINGS("HTTP2-Settings"), - - STRICT_TRANSPORT_SECURITY("Strict-Transport-Security"), - - /* ------------------------------------------------------------ */ - /** HTTP2 Fields. - */ - C_METHOD(":method"), - C_SCHEME(":scheme"), - C_AUTHORITY(":authority"), - C_PATH(":path"), - C_STATUS(":status"), - - UNKNOWN("::UNKNOWN::"); - - - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie<>(560); - static - { - for (HttpHeader header : HttpHeader.values()) - if (header!=UNKNOWN) - if (!CACHE.put(header.toString(),header)) - throw new IllegalStateException(); - } - - private final String _string; - private final byte[] _bytes; - private final byte[] _bytesColonSpace; - private final ByteBuffer _buffer; - - /* ------------------------------------------------------------ */ - HttpHeader(String s) - { - _string=s; - _bytes=StringUtil.getBytes(s); - _bytesColonSpace=StringUtil.getBytes(s+": "); - _buffer=ByteBuffer.wrap(_bytes); - } - - /* ------------------------------------------------------------ */ - public ByteBuffer toBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public byte[] getBytes() - { - return _bytes; - } - - /* ------------------------------------------------------------ */ - public byte[] getBytesColonSpace() - { - return _bytesColonSpace; - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return _string.equalsIgnoreCase(s); - } - - /* ------------------------------------------------------------ */ - public String asString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return _string; - } - -} - diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeaderValue.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeaderValue.java deleted file mode 100644 index 71301003ee6..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpHeaderValue.java +++ /dev/null @@ -1,104 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; -import java.util.EnumSet; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Trie; - - -/** - * - */ -public enum HttpHeaderValue -{ - CLOSE("close"), - CHUNKED("chunked"), - GZIP("gzip"), - IDENTITY("identity"), - KEEP_ALIVE("keep-alive"), - CONTINUE("100-continue"), - PROCESSING("102-processing"), - TE("TE"), - BYTES("bytes"), - NO_CACHE("no-cache"), - UPGRADE("Upgrade"), - UNKNOWN("::UNKNOWN::"); - - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); - static - { - for (HttpHeaderValue value : HttpHeaderValue.values()) - if (value!=UNKNOWN) - CACHE.put(value.toString(),value); - } - - private final String _string; - private final ByteBuffer _buffer; - - /* ------------------------------------------------------------ */ - HttpHeaderValue(String s) - { - _string=s; - _buffer=BufferUtil.toBuffer(s); - } - - /* ------------------------------------------------------------ */ - public ByteBuffer toBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return _string.equalsIgnoreCase(s); - } - - /* ------------------------------------------------------------ */ - public String asString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - private static EnumSet __known = - EnumSet.of(HttpHeader.CONNECTION, - HttpHeader.TRANSFER_ENCODING, - HttpHeader.CONTENT_ENCODING); - - /* ------------------------------------------------------------ */ - public static boolean hasKnownValues(HttpHeader header) - { - if (header==null) - return false; - return __known.contains(header); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpMethod.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpMethod.java deleted file mode 100644 index 1d2eeda0e53..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpMethod.java +++ /dev/null @@ -1,187 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.Trie; - - -/* ------------------------------------------------------------------------------- */ -/** - */ -public enum HttpMethod -{ - GET, - POST, - HEAD, - PUT, - OPTIONS, - DELETE, - TRACE, - CONNECT, - MOVE, - PROXY, - PRI; - - /* ------------------------------------------------------------ */ - /** - * Optimized lookup to find a method name and trailing space in a byte array. - * @param bytes Array containing ISO-8859-1 characters - * @param position The first valid index - * @param limit The first non valid index - * @return A HttpMethod if a match or null if no easy match. - */ - public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit) - { - int length=limit-position; - if (length<4) - return null; - switch(bytes[position]) - { - case 'G': - if (bytes[position+1]=='E' && bytes[position+2]=='T' && bytes[position+3]==' ') - return GET; - break; - case 'P': - if (bytes[position+1]=='O' && bytes[position+2]=='S' && bytes[position+3]=='T' && length>=5 && bytes[position+4]==' ') - return POST; - if (bytes[position+1]=='R' && bytes[position+2]=='O' && bytes[position+3]=='X' && length>=6 && bytes[position+4]=='Y' && bytes[position+5]==' ') - return PROXY; - if (bytes[position+1]=='U' && bytes[position+2]=='T' && bytes[position+3]==' ') - return PUT; - if (bytes[position+1]=='R' && bytes[position+2]=='I' && bytes[position+3]==' ') - return PRI; - break; - case 'H': - if (bytes[position+1]=='E' && bytes[position+2]=='A' && bytes[position+3]=='D' && length>=5 && bytes[position+4]==' ') - return HEAD; - break; - case 'O': - if (bytes[position+1]=='P' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 && - bytes[position+4]=='O' && bytes[position+5]=='N' && bytes[position+6]=='S' && bytes[position+7]==' ' ) - return OPTIONS; - break; - case 'D': - if (bytes[position+1]=='E' && bytes[position+2]=='L' && bytes[position+3]=='E' && length>=7 && - bytes[position+4]=='T' && bytes[position+5]=='E' && bytes[position+6]==' ' ) - return DELETE; - break; - case 'T': - if (bytes[position+1]=='R' && bytes[position+2]=='A' && bytes[position+3]=='C' && length>=6 && - bytes[position+4]=='E' && bytes[position+5]==' ' ) - return TRACE; - break; - case 'C': - if (bytes[position+1]=='O' && bytes[position+2]=='N' && bytes[position+3]=='N' && length>=8 && - bytes[position+4]=='E' && bytes[position+5]=='C' && bytes[position+6]=='T' && bytes[position+7]==' ' ) - return CONNECT; - break; - case 'M': - if (bytes[position+1]=='O' && bytes[position+2]=='V' && bytes[position+3]=='E' && length>=5 && bytes[position+4]==' ') - return MOVE; - break; - - default: - break; - } - return null; - } - - /* ------------------------------------------------------------ */ - /** - * Optimized lookup to find a method name and trailing space in a byte array. - * @param buffer buffer containing ISO-8859-1 characters, it is not modified. - * @return A HttpMethod if a match or null if no easy match. - */ - public static HttpMethod lookAheadGet(ByteBuffer buffer) - { - if (buffer.hasArray()) - return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit()); - - int l = buffer.remaining(); - if (l>=4) - { - HttpMethod m = CACHE.getBest(buffer,0,l); - if (m!=null) - { - int ml = m.asString().length(); - if (l>ml && buffer.get(buffer.position()+ml)==' ') - return m; - } - } - return null; - } - - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie<>(); - static - { - for (HttpMethod method : HttpMethod.values()) - CACHE.put(method.toString(),method); - } - - /* ------------------------------------------------------------ */ - private final ByteBuffer _buffer; - private final byte[] _bytes; - - /* ------------------------------------------------------------ */ - HttpMethod() - { - _bytes=StringUtil.getBytes(toString()); - _buffer=ByteBuffer.wrap(_bytes); - } - - /* ------------------------------------------------------------ */ - public byte[] getBytes() - { - return _bytes; - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return toString().equalsIgnoreCase(s); - } - - /* ------------------------------------------------------------ */ - public ByteBuffer asBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public String asString() - { - return toString(); - } - - /* ------------------------------------------------------------ */ - /** - * Converts the given String parameter to an HttpMethod - * @param method the String to get the equivalent HttpMethod from - * @return the HttpMethod or null if the parameter method is unknown - */ - public static HttpMethod fromString(String method) - { - return CACHE.get(method); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpParser.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpParser.java deleted file mode 100644 index 12f74a50bbf..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpParser.java +++ /dev/null @@ -1,1802 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Locale; - -import org.eclipse.jetty.http.HttpTokens.EndOfContent; -import org.eclipse.jetty.util.ArrayTernaryTrie; -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Trie; -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.Utf8StringBuilder; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -import static org.eclipse.jetty.http.HttpCompliance.LEGACY; -import static org.eclipse.jetty.http.HttpCompliance.RFC2616; -import static org.eclipse.jetty.http.HttpCompliance.RFC7230; -import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; -import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; -import static org.eclipse.jetty.http.HttpTokens.SPACE; -import static org.eclipse.jetty.http.HttpTokens.TAB; - - -/* ------------------------------------------------------------ */ -/** A Parser for 1.0 and 1.1 as defined by RFC7230 - *

- * This parser parses HTTP client and server messages from buffers - * passed in the {@link #parseNext(ByteBuffer)} method. The parsed - * elements of the HTTP message are passed as event calls to the - * {@link HttpHandler} instance the parser is constructed with. - * If the passed handler is a {@link RequestHandler} then server side - * parsing is performed and if it is a {@link ResponseHandler}, then - * client side parsing is done. - *

- *

- * The contract of the {@link HttpHandler} API is that if a call returns - * true then the call to {@link #parseNext(ByteBuffer)} will return as - * soon as possible also with a true response. Typically this indicates - * that the parsing has reached a stage where the caller should process - * the events accumulated by the handler. It is the preferred calling - * style that handling such as calling a servlet to process a request, - * should be done after a true return from {@link #parseNext(ByteBuffer)} - * rather than from within the scope of a call like - * {@link RequestHandler#messageComplete()} - *

- *

- * For performance, the parse is heavily dependent on the - * {@link Trie#getBest(ByteBuffer, int, int)} method to look ahead in a - * single pass for both the structure ( : and CRLF ) and semantic (which - * header and value) of a header. Specifically the static {@link HttpHeader#CACHE} - * is used to lookup common combinations of headers and values - * (eg. "Connection: close"), or just header names (eg. "Connection:" ). - * For headers who's value is not known statically (eg. Host, COOKIE) then a - * per parser dynamic Trie of {@link HttpFields} from previous parsed messages - * is used to help the parsing of subsequent messages. - *

- *

- * The parser can work in varying compliance modes: - *

- *
RFC7230
(default) Compliance with RFC7230
- *
RFC2616
Wrapped headers and HTTP/0.9 supported
- *
LEGACY
(aka STRICT) Adherence to Servlet Specification requirement for - * exact case of header names, bypassing the header caches, which are case insensitive, - * otherwise equivalent to RFC2616
- *
- * @see RFC 7230 - */ -public class HttpParser -{ - public static final Logger LOG = Log.getLogger(HttpParser.class); - @Deprecated - public final static String __STRICT="org.eclipse.jetty.http.HttpParser.STRICT"; - public final static int INITIAL_URI_LENGTH=256; - - /** - * Cache of common {@link HttpField}s including:
    - *
  • Common static combinations such as:
      - *
    • Connection: close - *
    • Accept-Encoding: gzip - *
    • Content-Length: 0 - *
    - *
  • Combinations of Content-Type header for common mime types by common charsets - *
  • Most common headers with null values so that a lookup will at least - * determine the header name even if the name:value combination is not cached - *
- */ - public final static Trie CACHE = new ArrayTrie<>(2048); - - // States - public enum State - { - START, - METHOD, - RESPONSE_VERSION, - SPACE1, - STATUS, - URI, - SPACE2, - REQUEST_VERSION, - REASON, - PROXY, - HEADER, - HEADER_IN_NAME, - HEADER_VALUE, - HEADER_IN_VALUE, - CONTENT, - EOF_CONTENT, - CHUNKED_CONTENT, - CHUNK_SIZE, - CHUNK_PARAMS, - CHUNK, - CHUNK_END, - END, - CLOSE, // The associated stream/endpoint should be closed - CLOSED // The associated stream/endpoint is at EOF - } - - private final static EnumSet __idleStates = EnumSet.of(State.START,State.END,State.CLOSE,State.CLOSED); - private final static EnumSet __completeStates = EnumSet.of(State.END,State.CLOSE,State.CLOSED); - - private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction - private final HttpHandler _handler; - private final RequestHandler _requestHandler; - private final ResponseHandler _responseHandler; - private final ComplianceHandler _complianceHandler; - private final int _maxHeaderBytes; - private final HttpCompliance _compliance; - private HttpField _field; - private HttpHeader _header; - private String _headerString; - private HttpHeaderValue _value; - private String _valueString; - private int _responseStatus; - private int _headerBytes; - private boolean _host; - - /* ------------------------------------------------------------------------------- */ - private volatile State _state=State.START; - private volatile boolean _eof; - private HttpMethod _method; - private String _methodString; - private HttpVersion _version; - private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune? - private EndOfContent _endOfContent; - private long _contentLength; - private long _contentPosition; - private int _chunkLength; - private int _chunkPosition; - private boolean _headResponse; - private boolean _cr; - private ByteBuffer _contentChunk; - private Trie _connectionFields; - - private int _length; - private final StringBuilder _string=new StringBuilder(); - - static - { - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE)); - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE)); - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE)); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")); - CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache")); - CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate")); - CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache")); - CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0")); - CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip")); - CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate")); - CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING,"chunked")); - CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT")); - - // Add common Content types as fields - for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/json","application/x-www-form-urlencoded"}) - { - HttpField field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type); - CACHE.put(field); - - for (String charset : new String[]{"utf-8","iso-8859-1"}) - { - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset)); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset)); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase(Locale.ENGLISH))); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase(Locale.ENGLISH))); - } - } - - // Add headers with null values so HttpParser can avoid looking up name again for unknown values - for (HttpHeader h:HttpHeader.values()) - if (!CACHE.put(new HttpField(h,(String)null))) - throw new IllegalStateException("CACHE FULL"); - // Add some more common headers - CACHE.put(new HttpField(HttpHeader.REFERER,(String)null)); - CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE,(String)null)); - CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH,(String)null)); - CACHE.put(new HttpField(HttpHeader.AUTHORIZATION,(String)null)); - CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null)); - } - - private static HttpCompliance compliance() - { - Boolean strict = Boolean.getBoolean(__STRICT); - return strict?HttpCompliance.LEGACY:HttpCompliance.RFC7230; - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler) - { - this(handler,-1,compliance()); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler) - { - this(handler,-1,compliance()); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes) - { - this(handler,maxHeaderBytes,compliance()); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes) - { - this(handler,maxHeaderBytes,compliance()); - } - - /* ------------------------------------------------------------------------------- */ - @Deprecated - public HttpParser(RequestHandler handler,int maxHeaderBytes,boolean strict) - { - this(handler,maxHeaderBytes,strict?HttpCompliance.LEGACY:compliance()); - } - - /* ------------------------------------------------------------------------------- */ - @Deprecated - public HttpParser(ResponseHandler handler,int maxHeaderBytes,boolean strict) - { - this(handler,maxHeaderBytes,strict?HttpCompliance.LEGACY:compliance()); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,HttpCompliance compliance) - { - this(handler,-1,compliance); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes,HttpCompliance compliance) - { - _handler=handler; - _requestHandler=handler; - _responseHandler=null; - _maxHeaderBytes=maxHeaderBytes; - _compliance=compliance==null?compliance():compliance; - _complianceHandler=(ComplianceHandler)(handler instanceof ComplianceHandler?handler:null); - } - - /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes,HttpCompliance compliance) - { - _handler=handler; - _requestHandler=null; - _responseHandler=handler; - _maxHeaderBytes=maxHeaderBytes; - _compliance=compliance==null?compliance():compliance; - _complianceHandler=(ComplianceHandler)(handler instanceof ComplianceHandler?handler:null); - } - - /* ------------------------------------------------------------------------------- */ - public HttpHandler getHandler() - { - return _handler; - } - - /* ------------------------------------------------------------------------------- */ - /** Check RFC compliance violation - * @param compliance The compliance level violated - * @param reason The reason for the violation - * @return True if the current compliance level is set so as to Not allow this violation - */ - protected boolean complianceViolation(HttpCompliance compliance,String reason) - { - if (_complianceHandler==null) - return _compliance.ordinal()>=compliance.ordinal(); - if (_compliance.ordinal()=State.CONTENT.ordinal() && _state.ordinal()0 && _state.ordinal() SPACE) - { - _string.setLength(0); - _string.append((char)ch); - setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION); - return false; - } - else if (ch==0) - break; - else if (ch<0) - throw new BadMessageException(); - - // count this white space as a header byte to avoid DOS - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) - { - LOG.warn("padding is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.BAD_REQUEST_400); - } - } - return false; - } - - /* ------------------------------------------------------------------------------- */ - private void setString(String s) - { - _string.setLength(0); - _string.append(s); - _length=s.length(); - } - - /* ------------------------------------------------------------------------------- */ - private String takeString() - { - _string.setLength(_length); - String s =_string.toString(); - _string.setLength(0); - _length=-1; - return s; - } - - /* ------------------------------------------------------------------------------- */ - /* Parse a request or response line - */ - private boolean parseLine(ByteBuffer buffer) - { - boolean handle=false; - - // Process headers - while (_state.ordinal()0 && ++_headerBytes>_maxHeaderBytes) - { - if (_state==State.URI) - { - LOG.warn("URI is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414); - } - else - { - if (_requestHandler!=null) - LOG.warn("request is too large >"+_maxHeaderBytes); - else - LOG.warn("response is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); - } - } - - switch (_state) - { - case METHOD: - if (ch == SPACE) - { - _length=_string.length(); - _methodString=takeString(); - HttpMethod method=HttpMethod.CACHE.get(_methodString); - if (method!=null) - _methodString=legacyString(_methodString,method.asString()); - setState(State.SPACE1); - } - else if (ch < SPACE) - { - if (ch==LINE_FEED) - throw new BadMessageException("No URI"); - else - throw new IllegalCharacterException(_state,ch,buffer); - } - else - _string.append((char)ch); - break; - - case RESPONSE_VERSION: - if (ch == HttpTokens.SPACE) - { - _length=_string.length(); - String version=takeString(); - _version=HttpVersion.CACHE.get(version); - if (_version==null) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); - setState(State.SPACE1); - } - else if (ch < HttpTokens.SPACE) - throw new IllegalCharacterException(_state,ch,buffer); - else - _string.append((char)ch); - break; - - case SPACE1: - if (ch > HttpTokens.SPACE || ch<0) - { - if (_responseHandler!=null) - { - setState(State.STATUS); - setResponseStatus(ch-'0'); - } - else - { - _uri.reset(); - setState(State.URI); - // quick scan for space or EoBuffer - if (buffer.hasArray()) - { - byte[] array=buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - int l=buffer.arrayOffset()+buffer.limit(); - int i=p; - while (iHttpTokens.SPACE) - i++; - - int len=i-p; - _headerBytes+=len; - - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) - { - LOG.warn("URI is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414); - } - _uri.append(array,p-1,len+1); - buffer.position(i-buffer.arrayOffset()); - } - else - _uri.append(ch); - } - } - else if (ch < HttpTokens.SPACE) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); - } - break; - - case STATUS: - if (ch == HttpTokens.SPACE) - { - setState(State.SPACE2); - } - else if (ch>='0' && ch<='9') - { - _responseStatus=_responseStatus*10+(ch-'0'); - } - else if (ch < HttpTokens.SPACE && ch>=0) - { - setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle; - } - else - { - throw new BadMessageException(); - } - break; - - case URI: - if (ch == HttpTokens.SPACE) - { - setState(State.SPACE2); - } - else if (ch < HttpTokens.SPACE && ch>=0) - { - // HTTP/0.9 - if (complianceViolation(RFC7230,"HTTP/0.9")) - throw new BadMessageException("HTTP/0.9 not supported"); - handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9); - setState(State.END); - BufferUtil.clear(buffer); - handle=_handler.headerComplete()||handle; - handle=_handler.messageComplete()||handle; - return handle; - } - else - { - _uri.append(ch); - } - break; - - case SPACE2: - if (ch > HttpTokens.SPACE) - { - _string.setLength(0); - _string.append((char)ch); - if (_responseHandler!=null) - { - _length=1; - setState(State.REASON); - } - else - { - setState(State.REQUEST_VERSION); - - // try quick look ahead for HTTP Version - HttpVersion version; - if (buffer.position()>0 && buffer.hasArray()) - version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit()); - else - version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining()); - - if (version!=null) - { - int pos = buffer.position()+version.asString().length()-1; - if (pos=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0) - { - int header_cache = _handler.getHeaderCacheSize(); - _connectionFields=new ArrayTernaryTrie<>(header_cache); - } - - setState(State.HEADER); - - handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle; - continue; - } - else if (ch>=HttpTokens.SPACE) - _string.append((char)ch); - else - throw new BadMessageException(); - - break; - - case REASON: - if (ch == HttpTokens.LINE_FEED) - { - String reason=takeString(); - setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle; - continue; - } - else if (ch>=HttpTokens.SPACE) - { - _string.append((char)ch); - if (ch!=' '&&ch!='\t') - _length=_string.length(); - } - else - throw new BadMessageException(); - break; - - default: - throw new IllegalStateException(_state.toString()); - - } - } - - return handle; - } - - private void parsedHeader() - { - // handler last header if any. Delayed to here just in case there was a continuation line (above) - if (_headerString!=null || _valueString!=null) - { - // Handle known headers - if (_header!=null) - { - boolean add_to_connection_trie=false; - switch (_header) - { - case CONTENT_LENGTH: - if (_endOfContent == EndOfContent.CONTENT_LENGTH) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Duplicate Content-Length"); - } - else if (_endOfContent != EndOfContent.CHUNKED_CONTENT) - { - _contentLength=convertContentLength(_valueString); - if (_contentLength <= 0) - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.CONTENT_LENGTH; - } - break; - - case TRANSFER_ENCODING: - if (_value==HttpHeaderValue.CHUNKED) - { - _endOfContent=EndOfContent.CHUNKED_CONTENT; - _contentLength=-1; - } - else - { - if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString())) - _endOfContent=EndOfContent.CHUNKED_CONTENT; - else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking"); - } - break; - - case HOST: - _host=true; - if (!(_field instanceof HostPortHttpField)) - { - _field=new HostPortHttpField(_header,legacyString(_headerString,_header.asString()),_valueString); - add_to_connection_trie=_connectionFields!=null; - } - break; - - case CONNECTION: - // Don't cache if not persistent - if (_valueString!=null && _valueString.contains("close")) - _connectionFields=null; - - break; - - case AUTHORIZATION: - case ACCEPT: - case ACCEPT_CHARSET: - case ACCEPT_ENCODING: - case ACCEPT_LANGUAGE: - case COOKIE: - case CACHE_CONTROL: - case USER_AGENT: - add_to_connection_trie=_connectionFields!=null && _field==null; - break; - - default: break; - } - - if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) - { - if (_field==null) - _field=new HttpField(_header,legacyString(_headerString,_header.asString()),_valueString); - _connectionFields.put(_field); - } - } - _handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString)); - } - - _headerString=_valueString=null; - _header=null; - _value=null; - _field=null; - } - - private long convertContentLength(String valueString) - { - try - { - return Long.parseLong(valueString); - } - catch(NumberFormatException e) - { - LOG.ignore(e); - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Invalid Content-Length Value"); - } - } - - /* ------------------------------------------------------------------------------- */ - /* - * Parse the message headers and return true if the handler has signaled for a return - */ - protected boolean parseHeaders(ByteBuffer buffer) - { - boolean handle=false; - - // Process headers - while (_state.ordinal()0 && ++_headerBytes>_maxHeaderBytes) - { - LOG.warn("Header is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); - } - - switch (_state) - { - case HEADER: - switch(ch) - { - case HttpTokens.COLON: - case HttpTokens.SPACE: - case HttpTokens.TAB: - { - if (complianceViolation(RFC7230,"header folding")) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding"); - - // header value without name - continuation? - if (_valueString==null) - { - _string.setLength(0); - _length=0; - } - else - { - setString(_valueString); - _string.append(' '); - _length++; - _valueString=null; - } - setState(State.HEADER_VALUE); - break; - } - - case HttpTokens.LINE_FEED: - { - // process previous header - parsedHeader(); - - _contentPosition=0; - - // End of headers! - - // Was there a required host header? - if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host"); - } - - // is it a response that cannot have a body? - if (_responseHandler !=null && // response - (_responseStatus == 304 || // not-modified response - _responseStatus == 204 || // no-content response - _responseStatus < 200)) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set - - // else if we don't know framing - else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) - { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.EOF_CONTENT; - } - - // How is the message ended? - switch (_endOfContent) - { - case EOF_CONTENT: - setState(State.EOF_CONTENT); - handle=_handler.headerComplete()||handle; - return handle; - - case CHUNKED_CONTENT: - setState(State.CHUNKED_CONTENT); - handle=_handler.headerComplete()||handle; - return handle; - - case NO_CONTENT: - setState(State.END); - handle=_handler.headerComplete()||handle; - handle=_handler.messageComplete()||handle; - return handle; - - default: - setState(State.CONTENT); - handle=_handler.headerComplete()||handle; - return handle; - } - } - - default: - { - // now handle the ch - if (chHttpTokens.SPACE) - { - if (_header!=null) - { - setString(_header.asString()); - _header=null; - _headerString=null; - } - - _string.append((char)ch); - if (ch>HttpTokens.SPACE) - _length=_string.length(); - break; - } - - if (ch==HttpTokens.LINE_FEED && !complianceViolation(RFC7230,"name only header")) - { - if (_headerString==null) - { - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - } - _value=null; - _string.setLength(0); - _valueString=""; - _length=-1; - - setState(State.HEADER); - break; - } - - throw new IllegalCharacterException(_state,ch,buffer); - - case HEADER_VALUE: - if (ch>HttpTokens.SPACE || ch<0) - { - _string.append((char)(0xff&ch)); - _length=_string.length(); - setState(State.HEADER_IN_VALUE); - break; - } - - if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB) - break; - - if (ch==HttpTokens.LINE_FEED) - { - _value=null; - _string.setLength(0); - _valueString=""; - _length=-1; - - setState(State.HEADER); - break; - } - throw new IllegalCharacterException(_state,ch,buffer); - - case HEADER_IN_VALUE: - if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB) - { - if (_valueString!=null) - { - setString(_valueString); - _valueString=null; - _field=null; - } - _string.append((char)(0xff&ch)); - if (ch>HttpTokens.SPACE || ch<0) - _length=_string.length(); - break; - } - - if (ch==HttpTokens.LINE_FEED) - { - if (_length > 0) - { - _value=null; - _valueString=takeString(); - _length=-1; - } - setState(State.HEADER); - break; - } - - throw new IllegalCharacterException(_state,ch,buffer); - - default: - throw new IllegalStateException(_state.toString()); - - } - } - - return handle; - } - - /* ------------------------------------------------------------------------------- */ - /** - * Parse until next Event. - * @param buffer the buffer to parse - * @return True if an {@link RequestHandler} method was called and it returned true; - */ - public boolean parseNext(ByteBuffer buffer) - { - if (DEBUG) - LOG.debug("parseNext s={} {}",_state,BufferUtil.toDetailString(buffer)); - try - { - // Start a request/response - if (_state==State.START) - { - _version=null; - _method=null; - _methodString=null; - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - _header=null; - if (quickStart(buffer)) - return true; - } - - // Request/response line - if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()= State.HEADER.ordinal() && _state.ordinal()= State.CONTENT.ordinal() && _state.ordinal()0 && _headResponse) - { - setState(State.END); - return _handler.messageComplete(); - } - else - { - if (parseContent(buffer)) - return true; - } - } - - // handle end states - if (_state==State.END) - { - // eat white space - while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE) - buffer.get(); - } - else if (_state==State.CLOSE) - { - // Seeking EOF - if (BufferUtil.hasContent(buffer)) - { - // Just ignore data when closed - _headerBytes+=buffer.remaining(); - BufferUtil.clear(buffer); - if (_maxHeaderBytes>0 && _headerBytes>_maxHeaderBytes) - { - // Don't want to waste time reading data of a closed request - throw new IllegalStateException("too much data seeking EOF"); - } - } - } - else if (_state==State.CLOSED) - { - BufferUtil.clear(buffer); - } - - // Handle EOF - if (_eof && !buffer.hasRemaining()) - { - switch(_state) - { - case CLOSED: - break; - - case START: - setState(State.CLOSED); - _handler.earlyEOF(); - break; - - case END: - case CLOSE: - setState(State.CLOSED); - break; - - case EOF_CONTENT: - setState(State.CLOSED); - return _handler.messageComplete(); - - case CONTENT: - case CHUNKED_CONTENT: - case CHUNK_SIZE: - case CHUNK_PARAMS: - case CHUNK: - setState(State.CLOSED); - _handler.earlyEOF(); - break; - - default: - if (DEBUG) - LOG.debug("{} EOF in {}",this,_state); - setState(State.CLOSED); - _handler.badMessage(400,null); - break; - } - } - } - catch(BadMessageException e) - { - BufferUtil.clear(buffer); - - Throwable cause = e.getCause(); - boolean stack = LOG.isDebugEnabled() || - (!(cause instanceof NumberFormatException ) && (cause instanceof RuntimeException || cause instanceof Error)); - - if (stack) - LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler,e); - else - LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler); - setState(State.CLOSE); - _handler.badMessage(e.getCode(), e.getReason()); - } - catch(NumberFormatException|IllegalStateException e) - { - BufferUtil.clear(buffer); - LOG.warn("parse exception: {} in {} for {}",e.toString(),_state,_handler); - if (DEBUG) - LOG.debug(e); - - switch(_state) - { - case CLOSED: - break; - case CLOSE: - _handler.earlyEOF(); - break; - default: - setState(State.CLOSE); - _handler.badMessage(400,"Bad Message "+e.toString()); - } - } - catch(Exception|Error e) - { - BufferUtil.clear(buffer); - - LOG.warn("parse exception: "+e.toString()+" for "+_handler,e); - - switch(_state) - { - case CLOSED: - break; - case CLOSE: - _handler.earlyEOF(); - break; - default: - setState(State.CLOSE); - _handler.badMessage(400,null); - } - } - return false; - } - - protected boolean parseContent(ByteBuffer buffer) - { - int remaining=buffer.remaining(); - if (remaining==0 && _state==State.CONTENT) - { - long content=_contentLength - _contentPosition; - if (content == 0) - { - setState(State.END); - return _handler.messageComplete(); - } - } - - // Handle _content - byte ch; - while (_state.ordinal() < State.END.ordinal() && remaining>0) - { - switch (_state) - { - case EOF_CONTENT: - _contentChunk=buffer.asReadOnlyBuffer(); - _contentPosition += remaining; - buffer.position(buffer.position()+remaining); - if (_handler.content(_contentChunk)) - return true; - break; - - case CONTENT: - { - long content=_contentLength - _contentPosition; - if (content == 0) - { - setState(State.END); - return _handler.messageComplete(); - } - else - { - _contentChunk=buffer.asReadOnlyBuffer(); - - // limit content by expected size - if (remaining > content) - { - // We can cast remaining to an int as we know that it is smaller than - // or equal to length which is already an int. - _contentChunk.limit(_contentChunk.position()+(int)content); - } - - _contentPosition += _contentChunk.remaining(); - buffer.position(buffer.position()+_contentChunk.remaining()); - - if (_handler.content(_contentChunk)) - return true; - - if(_contentPosition == _contentLength) - { - setState(State.END); - return _handler.messageComplete(); - } - } - break; - } - - case CHUNKED_CONTENT: - { - ch=next(buffer); - if (ch>HttpTokens.SPACE) - { - _chunkLength=TypeUtil.convertHexDigit(ch); - _chunkPosition=0; - setState(State.CHUNK_SIZE); - } - - break; - } - - case CHUNK_SIZE: - { - ch=next(buffer); - if (ch==0) - break; - if (ch == HttpTokens.LINE_FEED) - { - if (_chunkLength == 0) - setState(State.CHUNK_END); - else - setState(State.CHUNK); - } - else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) - setState(State.CHUNK_PARAMS); - else - _chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch); - break; - } - - case CHUNK_PARAMS: - { - ch=next(buffer); - if (ch == HttpTokens.LINE_FEED) - { - if (_chunkLength == 0) - setState(State.CHUNK_END); - else - setState(State.CHUNK); - } - break; - } - - case CHUNK: - { - int chunk=_chunkLength - _chunkPosition; - if (chunk == 0) - { - setState(State.CHUNKED_CONTENT); - } - else - { - _contentChunk=buffer.asReadOnlyBuffer(); - - if (remaining > chunk) - _contentChunk.limit(_contentChunk.position()+chunk); - chunk=_contentChunk.remaining(); - - _contentPosition += chunk; - _chunkPosition += chunk; - buffer.position(buffer.position()+chunk); - if (_handler.content(_contentChunk)) - return true; - } - break; - } - - case CHUNK_END: - { - // TODO handle chunk trailer - ch=next(buffer); - if (ch==0) - break; - if (ch == HttpTokens.LINE_FEED) - { - setState(State.END); - return _handler.messageComplete(); - } - throw new IllegalCharacterException(_state,ch,buffer); - } - - case CLOSED: - { - BufferUtil.clear(buffer); - return false; - } - - default: - break; - - } - - remaining=buffer.remaining(); - } - return false; - } - - /* ------------------------------------------------------------------------------- */ - public boolean isAtEOF() - - { - return _eof; - } - - /* ------------------------------------------------------------------------------- */ - /** Signal that the associated data source is at EOF - */ - public void atEOF() - { - if (DEBUG) - LOG.debug("atEOF {}", this); - _eof=true; - } - - /* ------------------------------------------------------------------------------- */ - /** Request that the associated data source be closed - */ - public void close() - { - if (DEBUG) - LOG.debug("close {}", this); - setState(State.CLOSE); - } - - /* ------------------------------------------------------------------------------- */ - public void reset() - { - if (DEBUG) - LOG.debug("reset {}", this); - - // reset state - if (_state==State.CLOSE || _state==State.CLOSED) - return; - - setState(State.START); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - _contentLength=-1; - _contentPosition=0; - _responseStatus=0; - _contentChunk=null; - _headerBytes=0; - _host=false; - } - - /* ------------------------------------------------------------------------------- */ - protected void setState(State state) - { - if (DEBUG) - LOG.debug("{} --> {}",_state,state); - _state=state; - } - - /* ------------------------------------------------------------------------------- */ - public Trie getFieldCache() - { - return _connectionFields; - } - - /* ------------------------------------------------------------------------------- */ - private String getProxyField(ByteBuffer buffer) - { - _string.setLength(0); - _length=0; - - while (buffer.hasRemaining()) - { - // process each character - byte ch=next(buffer); - if (ch<=' ') - return _string.toString(); - _string.append((char)ch); - } - throw new BadMessageException(); - } - - /* ------------------------------------------------------------------------------- */ - @Override - public String toString() - { - return String.format("%s{s=%s,%d of %d}", - getClass().getSimpleName(), - _state, - _contentPosition, - _contentLength); - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* Event Handler interface - * These methods return true if the caller should process the events - * so far received (eg return from parseNext and call HttpChannel.handle). - * If multiple callbacks are called in sequence (eg - * headerComplete then messageComplete) from the same point in the parsing - * then it is sufficient for the caller to process the events only once. - */ - public interface HttpHandler - { - public boolean content(ByteBuffer item); - - public boolean headerComplete(); - - public boolean messageComplete(); - - /** - * This is the method called by parser when a HTTP Header name and value is found - * @param field The field parsed - */ - public void parsedHeader(HttpField field); - - /* ------------------------------------------------------------ */ - /** Called to signal that an EOF was received unexpectedly - * during the parsing of a HTTP message - */ - public void earlyEOF(); - - /* ------------------------------------------------------------ */ - /** Called to signal that a bad HTTP message has been received. - * @param status The bad status to send - * @param reason The textual reason for badness - */ - public void badMessage(int status, String reason); - - /* ------------------------------------------------------------ */ - /** @return the size in bytes of the per parser header cache - */ - public int getHeaderCacheSize(); - } - - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - public interface RequestHandler extends HttpHandler - { - /** - * This is the method called by parser when the HTTP request line is parsed - * @param method The method - * @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused. - * @param version the http version in use - * @return true if handling parsing should return. - */ - public boolean startRequest(String method, String uri, HttpVersion version); - - } - - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - public interface ResponseHandler extends HttpHandler - { - /** - * This is the method called by parser when the HTTP request line is parsed - * @param version the http version in use - * @param status the response status - * @param reason the response reason phrase - * @return true if handling parsing should return - */ - public boolean startResponse(HttpVersion version, int status, String reason); - } - - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - public interface ComplianceHandler extends HttpHandler - { - public void onComplianceViolation(HttpCompliance compliance,HttpCompliance required,String reason); - } - - /* ------------------------------------------------------------------------------- */ - @SuppressWarnings("serial") - private static class IllegalCharacterException extends BadMessageException - { - private IllegalCharacterException(State state,byte ch,ByteBuffer buffer) - { - super(400,String.format("Illegal character 0x%X",ch)); - // Bug #460642 - don't reveal buffers to end user - LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s",ch,state,BufferUtil.toDetailString(buffer))); - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpScheme.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpScheme.java deleted file mode 100644 index 44ac0c6bc7f..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpScheme.java +++ /dev/null @@ -1,79 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Trie; - -/* ------------------------------------------------------------------------------- */ -/** - */ -public enum HttpScheme -{ - HTTP("http"), - HTTPS("https"), - WS("ws"), - WSS("wss"); - - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); - static - { - for (HttpScheme version : HttpScheme.values()) - CACHE.put(version.asString(),version); - } - - private final String _string; - private final ByteBuffer _buffer; - - /* ------------------------------------------------------------ */ - HttpScheme(String s) - { - _string=s; - _buffer=BufferUtil.toBuffer(s); - } - - /* ------------------------------------------------------------ */ - public ByteBuffer asByteBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return s!=null && _string.equalsIgnoreCase(s); - } - - public String asString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return _string; - } - -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpStatus.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpStatus.java deleted file mode 100644 index 56828895375..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpStatus.java +++ /dev/null @@ -1,1076 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -/** - *

- * HttpStatusCode enum class, for status codes based on various HTTP RFCs. (see - * table below) - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
HTTP Status Codes Table
EnumCodeMessage - * RFC 1945 - HTTP/1.0 - * RFC 7231 - HTTP/1.1 Semantics and Content - * RFC 7238 - HTTP/1.1 Permanent Redirect - * RFC 2518 - WEBDAV
Informational - 1xx{@link #isInformational(int)}
{@link #CONTINUE_100}100Continue  - * Sec. 6.2.1 
{@link #SWITCHING_PROTOCOLS_101}101Switching Protocols  - * Sec. 6.2.2 
{@link #PROCESSING_102}102Processing   - * Sec. 10.1
Success - 2xx{@link #isSuccess(int)}
{@link #OK_200}200OK - * Sec. 9.2 - * Sec. 6.3.1 
{@link #CREATED_201}201Created - * Sec. 9.2 - * Sec. 6.3.2 
{@link #ACCEPTED_202}202Accepted - * Sec. 9.2 - * Sec. 6.3.3 
{@link #NON_AUTHORITATIVE_INFORMATION_203}203Non Authoritative Information  - * Sec. 6.3.4 
{@link #NO_CONTENT_204}204No Content - * Sec. 9.2 - * Sec. 6.3.5 
{@link #RESET_CONTENT_205}205Reset Content  - * Sec. 6.3.6 
{@link #PARTIAL_CONTENT_206}206Partial Content  - * Sec. 6.3.7 
{@link #MULTI_STATUS_207}207Multi-Status   - * Sec. 10.2
 207Partial Update OK  - * draft/01 
Redirection - 3xx{@link #isRedirection(int)}
{@link #MULTIPLE_CHOICES_300}300Multiple Choices - * Sec. 9.3 - * Sec. 6.4.1 
{@link #MOVED_PERMANENTLY_301}301Moved Permanently - * Sec. 9.3 - * Sec. 6.4.2 
{@link #MOVED_TEMPORARILY_302}302Moved Temporarily - * Sec. 9.3(now "302 Found") 
{@link #FOUND_302}302Found(was "302 Moved Temporarily") - * Sec. 6.4.3 
{@link #SEE_OTHER_303}303See Other  - * Sec. 6.4.4 
{@link #NOT_MODIFIED_304}304Not Modified - * Sec. 9.3 - * Sec. 6.4.5 
{@link #USE_PROXY_305}305Use Proxy  - * Sec. 6.4.6 
 306(Unused)  - * Sec. 6.4.7 
{@link #TEMPORARY_REDIRECT_307}307Temporary Redirect  - * Sec. 6.4.8 
{@link #PERMANENT_REDIRECT_308}307Permanent Redirect  - * RFC7238 
Client Error - 4xx{@link #isClientError(int)}
{@link #BAD_REQUEST_400}400Bad Request - * Sec. 9.4 - * Sec. 6.5.1 
{@link #UNAUTHORIZED_401}401Unauthorized - * Sec. 9.4 - * Sec. 6.5.2 
{@link #PAYMENT_REQUIRED_402}402Payment Required - * Sec. 9.4 - * Sec. 6.5.3 
{@link #FORBIDDEN_403}403Forbidden - * Sec. 9.4 - * Sec. 6.5.4 
{@link #NOT_FOUND_404}404Not Found - * Sec. 9.4 - * Sec. 6.5.5 
{@link #METHOD_NOT_ALLOWED_405}405Method Not Allowed  - * Sec. 6.5.6 
{@link #NOT_ACCEPTABLE_406}406Not Acceptable  - * Sec. 6.5.7 
{@link #PROXY_AUTHENTICATION_REQUIRED_407}407Proxy Authentication Required  - * Sec. 6.5.8 
{@link #REQUEST_TIMEOUT_408}408Request Timeout  - * Sec. 6.5.9 
{@link #CONFLICT_409}409Conflict  - * Sec. 10.4.10 - *  
{@link #GONE_410}410Gone  - * Sec. 10.4.11 - *  
{@link #LENGTH_REQUIRED_411}411Length Required  - * Sec. 10.4.12 - *  
{@link #PRECONDITION_FAILED_412}412Precondition Failed  - * Sec. 10.4.13 - *  
{@link #REQUEST_ENTITY_TOO_LARGE_413}413Request Entity Too Large  - * Sec. 10.4.14 - *  
{@link #REQUEST_URI_TOO_LONG_414}414Request-URI Too Long  - * Sec. 10.4.15 - *  
{@link #UNSUPPORTED_MEDIA_TYPE_415}415Unsupported Media Type  - * Sec. 10.4.16 - *  
{@link #REQUESTED_RANGE_NOT_SATISFIABLE_416}416Requested Range Not Satisfiable  - * Sec. 10.4.17 - *  
{@link #EXPECTATION_FAILED_417}417Expectation Failed  - * Sec. 10.4.18 - *  
 418Reauthentication Required  - * draft/01 
 418Unprocessable Entity   - * draft/05
 419Proxy Reauthentication Required  - * draft/01 
 419Insufficient Space on Resource   - * draft/05
 420Method Failure   - * draft/05
 421(Unused)   
{@link #UNPROCESSABLE_ENTITY_422}422Unprocessable Entity   - * Sec. 10.3
{@link #LOCKED_423}423Locked   - * Sec. 10.4
{@link #FAILED_DEPENDENCY_424}424Failed Dependency   - * Sec. 10.5
Server Error - 5xx{@link #isServerError(int)}
{@link #INTERNAL_SERVER_ERROR_500}500Internal Server Error - * Sec. 9.5 - * Sec. 6.6.1 
{@link #NOT_IMPLEMENTED_501}501Not Implemented - * Sec. 9.5 - * Sec. 6.6.2 
{@link #BAD_GATEWAY_502}502Bad Gateway - * Sec. 9.5 - * Sec. 6.6.3 
{@link #SERVICE_UNAVAILABLE_503}503Service Unavailable - * Sec. 9.5 - * Sec. 6.6.4 
{@link #GATEWAY_TIMEOUT_504}504Gateway Timeout  - * Sec. 6.6.5 
{@link #HTTP_VERSION_NOT_SUPPORTED_505}505HTTP Version Not Supported  - * Sec. 6.6.6 
 506(Unused)   
{@link #INSUFFICIENT_STORAGE_507}507Insufficient Storage   - * Sec. 10.6
- * - * @version $Id$ - */ -public class HttpStatus -{ - public final static int CONTINUE_100 = 100; - public final static int SWITCHING_PROTOCOLS_101 = 101; - public final static int PROCESSING_102 = 102; - - public final static int OK_200 = 200; - public final static int CREATED_201 = 201; - public final static int ACCEPTED_202 = 202; - public final static int NON_AUTHORITATIVE_INFORMATION_203 = 203; - public final static int NO_CONTENT_204 = 204; - public final static int RESET_CONTENT_205 = 205; - public final static int PARTIAL_CONTENT_206 = 206; - public final static int MULTI_STATUS_207 = 207; - - public final static int MULTIPLE_CHOICES_300 = 300; - public final static int MOVED_PERMANENTLY_301 = 301; - public final static int MOVED_TEMPORARILY_302 = 302; - public final static int FOUND_302 = 302; - public final static int SEE_OTHER_303 = 303; - public final static int NOT_MODIFIED_304 = 304; - public final static int USE_PROXY_305 = 305; - public final static int TEMPORARY_REDIRECT_307 = 307; - public final static int PERMANENT_REDIRECT_308 = 308; - - public final static int BAD_REQUEST_400 = 400; - public final static int UNAUTHORIZED_401 = 401; - public final static int PAYMENT_REQUIRED_402 = 402; - public final static int FORBIDDEN_403 = 403; - public final static int NOT_FOUND_404 = 404; - public final static int METHOD_NOT_ALLOWED_405 = 405; - public final static int NOT_ACCEPTABLE_406 = 406; - public final static int PROXY_AUTHENTICATION_REQUIRED_407 = 407; - public final static int REQUEST_TIMEOUT_408 = 408; - public final static int CONFLICT_409 = 409; - public final static int GONE_410 = 410; - public final static int LENGTH_REQUIRED_411 = 411; - public final static int PRECONDITION_FAILED_412 = 412; - public final static int REQUEST_ENTITY_TOO_LARGE_413 = 413; - public final static int REQUEST_URI_TOO_LONG_414 = 414; - public final static int UNSUPPORTED_MEDIA_TYPE_415 = 415; - public final static int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416; - public final static int EXPECTATION_FAILED_417 = 417; - public final static int MISDIRECTED_REQUEST_421 = 421; - public final static int UNPROCESSABLE_ENTITY_422 = 422; - public final static int LOCKED_423 = 423; - public final static int FAILED_DEPENDENCY_424 = 424; - public final static int UPGRADE_REQUIRED_426 = 426; - - public final static int INTERNAL_SERVER_ERROR_500 = 500; - public final static int NOT_IMPLEMENTED_501 = 501; - public final static int BAD_GATEWAY_502 = 502; - public final static int SERVICE_UNAVAILABLE_503 = 503; - public final static int GATEWAY_TIMEOUT_504 = 504; - public final static int HTTP_VERSION_NOT_SUPPORTED_505 = 505; - public final static int INSUFFICIENT_STORAGE_507 = 507; - - // RFC 6585 - public final static int PRECONDITION_REQUIRED_428 = 428; - public final static int TOO_MANY_REQUESTS_429 = 429; - public final static int REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431; - public final static int NETWORK_AUTHENTICATION_REQUIRED_511 = 511; - - public static final int MAX_CODE = 511; - - private static final Code[] codeMap = new Code[MAX_CODE+1]; - - static - { - for (Code code : Code.values()) - { - codeMap[code._code] = code; - } - } - - - public enum Code - { - /* - * -------------------------------------------------------------------- - * Informational messages in 1xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV - */ - - /** 100 Continue */ - CONTINUE(CONTINUE_100, "Continue"), - /** 101 Switching Protocols */ - SWITCHING_PROTOCOLS(SWITCHING_PROTOCOLS_101, "Switching Protocols"), - /** 102 Processing */ - PROCESSING(PROCESSING_102, "Processing"), - - /* - * -------------------------------------------------------------------- - * Success messages in 2xx series. As defined by ... RFC 1945 - HTTP/1.0 - * RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV - */ - - /** 200 OK */ - OK(OK_200, "OK"), - /** 201 Created */ - CREATED(CREATED_201, "Created"), - /** 202 Accepted */ - ACCEPTED(ACCEPTED_202, "Accepted"), - /** 203 Non Authoritative Information */ - NON_AUTHORITATIVE_INFORMATION(NON_AUTHORITATIVE_INFORMATION_203, "Non Authoritative Information"), - /** 204 No Content */ - NO_CONTENT(NO_CONTENT_204, "No Content"), - /** 205 Reset Content */ - RESET_CONTENT(RESET_CONTENT_205, "Reset Content"), - /** 206 Partial Content */ - PARTIAL_CONTENT(PARTIAL_CONTENT_206, "Partial Content"), - /** 207 Multi-Status */ - MULTI_STATUS(MULTI_STATUS_207, "Multi-Status"), - - /* - * -------------------------------------------------------------------- - * Redirection messages in 3xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 7231 - HTTP/1.1 - */ - - /** 300 Mutliple Choices */ - MULTIPLE_CHOICES(MULTIPLE_CHOICES_300, "Multiple Choices"), - /** 301 Moved Permanently */ - MOVED_PERMANENTLY(MOVED_PERMANENTLY_301, "Moved Permanently"), - /** 302 Moved Temporarily */ - MOVED_TEMPORARILY(MOVED_TEMPORARILY_302, "Moved Temporarily"), - /** 302 Found */ - FOUND(FOUND_302, "Found"), - /** 303 See Other */ - SEE_OTHER(SEE_OTHER_303, "See Other"), - /** 304 Not Modified */ - NOT_MODIFIED(NOT_MODIFIED_304, "Not Modified"), - /** 305 Use Proxy */ - USE_PROXY(USE_PROXY_305, "Use Proxy"), - /** 307 Temporary Redirect */ - TEMPORARY_REDIRECT(TEMPORARY_REDIRECT_307, "Temporary Redirect"), - /** 308 Permanent Redirect */ - PERMANET_REDIRECT(PERMANENT_REDIRECT_308, "Permanent Redirect"), - - /* - * -------------------------------------------------------------------- - * Client Error messages in 4xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV - */ - - /** 400 Bad Request */ - BAD_REQUEST(BAD_REQUEST_400, "Bad Request"), - /** 401 Unauthorized */ - UNAUTHORIZED(UNAUTHORIZED_401, "Unauthorized"), - /** 402 Payment Required */ - PAYMENT_REQUIRED(PAYMENT_REQUIRED_402, "Payment Required"), - /** 403 Forbidden */ - FORBIDDEN(FORBIDDEN_403, "Forbidden"), - /** 404 Not Found */ - NOT_FOUND(NOT_FOUND_404, "Not Found"), - /** 405 Method Not Allowed */ - METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED_405, "Method Not Allowed"), - /** 406 Not Acceptable */ - NOT_ACCEPTABLE(NOT_ACCEPTABLE_406, "Not Acceptable"), - /** 407 Proxy Authentication Required */ - PROXY_AUTHENTICATION_REQUIRED(PROXY_AUTHENTICATION_REQUIRED_407, "Proxy Authentication Required"), - /** 408 Request Timeout */ - REQUEST_TIMEOUT(REQUEST_TIMEOUT_408, "Request Timeout"), - /** 409 Conflict */ - CONFLICT(CONFLICT_409, "Conflict"), - /** 410 Gone */ - GONE(GONE_410, "Gone"), - /** 411 Length Required */ - LENGTH_REQUIRED(LENGTH_REQUIRED_411, "Length Required"), - /** 412 Precondition Failed */ - PRECONDITION_FAILED(PRECONDITION_FAILED_412, "Precondition Failed"), - /** 413 Request Entity Too Large */ - REQUEST_ENTITY_TOO_LARGE(REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large"), - /** 414 Request-URI Too Long */ - REQUEST_URI_TOO_LONG(REQUEST_URI_TOO_LONG_414, "Request-URI Too Long"), - /** 415 Unsupported Media Type */ - UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Media Type"), - /** 416 Requested Range Not Satisfiable */ - REQUESTED_RANGE_NOT_SATISFIABLE(REQUESTED_RANGE_NOT_SATISFIABLE_416, "Requested Range Not Satisfiable"), - /** 417 Expectation Failed */ - EXPECTATION_FAILED(EXPECTATION_FAILED_417, "Expectation Failed"), - /** 421 Misdirected Request(RFC7234)y */ - MISDIRECTED_REQUEST(MISDIRECTED_REQUEST_421, "Misdirected Request"), - /** 422 Unprocessable Entity */ - UNPROCESSABLE_ENTITY(UNPROCESSABLE_ENTITY_422, "Unprocessable Entity"), - /** 423 Locked */ - LOCKED(LOCKED_423, "Locked"), - /** 424 Failed Dependency */ - FAILED_DEPENDENCY(FAILED_DEPENDENCY_424, "Failed Dependency"), - - /** 426 Upgrade Required (RFC7231) */ - UPGRADE_REQUIRED(UPGRADE_REQUIRED_426, "Upgrade Required"), - - /** 428 Precondition Required (RFC6585) */ - PRECONDITION_REQUIRED(PRECONDITION_REQUIRED_428, "Precondition Required"), - /** 429 Too Many Requests (RFC6585) */ - TOO_MANY_REQUESTS(TOO_MANY_REQUESTS_429, "Too Many Requests"), - /** 431 Request Header Fields Too Large (RFC6585) */ - REQUEST_HEADER_FIELDS_TOO_LARGE(REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Request Header Fields Too Large"), - - /* - * -------------------------------------------------------------------- - * Server Error messages in 5xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV - */ - - /** 500 Server Error */ - INTERNAL_SERVER_ERROR(INTERNAL_SERVER_ERROR_500, "Server Error"), - /** 501 Not Implemented */ - NOT_IMPLEMENTED(NOT_IMPLEMENTED_501, "Not Implemented"), - /** 502 Bad Gateway */ - BAD_GATEWAY(BAD_GATEWAY_502, "Bad Gateway"), - /** 503 Service Unavailable */ - SERVICE_UNAVAILABLE(SERVICE_UNAVAILABLE_503, "Service Unavailable"), - /** 504 Gateway Timeout */ - GATEWAY_TIMEOUT(GATEWAY_TIMEOUT_504, "Gateway Timeout"), - /** 505 HTTP Version Not Supported */ - HTTP_VERSION_NOT_SUPPORTED(HTTP_VERSION_NOT_SUPPORTED_505, "HTTP Version Not Supported"), - /** 507 Insufficient Storage */ - INSUFFICIENT_STORAGE(INSUFFICIENT_STORAGE_507, "Insufficient Storage"), - - /** 511 Network Authentication Required (RFC6585) */ - NETWORK_AUTHENTICATION_REQUIRED(NETWORK_AUTHENTICATION_REQUIRED_511, "Network Authentication Required"), - - ; - - private final int _code; - private final String _message; - - private Code(int code, String message) - { - this._code = code; - _message=message; - } - - public int getCode() - { - return _code; - } - - public String getMessage() - { - return _message; - } - - - public boolean equals(int code) - { - return (this._code == code); - } - - @Override - public String toString() - { - return String.format("[%03d %s]",this._code,this.getMessage()); - } - - /** - * Simple test against an code to determine if it falls into the - * Informational message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 7231 - - * HTTP/1.1. - * - * @return true if within range of codes that belongs to - * Informational messages. - */ - public boolean isInformational() - { - return HttpStatus.isInformational(this._code); - } - - /** - * Simple test against an code to determine if it falls into the - * Success message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 7231 - - * HTTP/1.1. - * - * @return true if within range of codes that belongs to - * Success messages. - */ - public boolean isSuccess() - { - return HttpStatus.isSuccess(this._code); - } - - /** - * Simple test against an code to determine if it falls into the - * Redirection message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 7231 - - * HTTP/1.1. - * - * @return true if within range of codes that belongs to - * Redirection messages. - */ - public boolean isRedirection() - { - return HttpStatus.isRedirection(this._code); - } - - /** - * Simple test against an code to determine if it falls into the - * Client Error message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 7231 - - * HTTP/1.1. - * - * @return true if within range of codes that belongs to - * Client Error messages. - */ - public boolean isClientError() - { - return HttpStatus.isClientError(this._code); - } - - /** - * Simple test against an code to determine if it falls into the - * Server Error message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 7231 - - * HTTP/1.1. - * - * @return true if within range of codes that belongs to - * Server Error messages. - */ - public boolean isServerError() - { - return HttpStatus.isServerError(this._code); - } - } - - - /** - * Get the HttpStatusCode for a specific code - * - * @param code - * the code to lookup. - * @return the {@link HttpStatus} if found, or null if not found. - */ - public static Code getCode(int code) - { - if (code <= MAX_CODE) - { - return codeMap[code]; - } - return null; - } - - /** - * Get the status message for a specific code. - * - * @param code - * the code to look up - * @return the specific message, or the code number itself if code - * does not match known list. - */ - public static String getMessage(int code) - { - Code codeEnum = getCode(code); - if (codeEnum != null) - { - return codeEnum.getMessage(); - } - else - { - return Integer.toString(code); - } - } - - /** - * Simple test against an code to determine if it falls into the - * Informational message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. - * - * @param code - * the code to test. - * @return true if within range of codes that belongs to - * Informational messages. - */ - public static boolean isInformational(int code) - { - return ((100 <= code) && (code <= 199)); - } - - /** - * Simple test against an code to determine if it falls into the - * Success message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. - * - * @param code - * the code to test. - * @return true if within range of codes that belongs to - * Success messages. - */ - public static boolean isSuccess(int code) - { - return ((200 <= code) && (code <= 299)); - } - - /** - * Simple test against an code to determine if it falls into the - * Redirection message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. - * - * @param code - * the code to test. - * @return true if within range of codes that belongs to - * Redirection messages. - */ - public static boolean isRedirection(int code) - { - return ((300 <= code) && (code <= 399)); - } - - /** - * Simple test against an code to determine if it falls into the - * Client Error message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. - * - * @param code - * the code to test. - * @return true if within range of codes that belongs to - * Client Error messages. - */ - public static boolean isClientError(int code) - { - return ((400 <= code) && (code <= 499)); - } - - /** - * Simple test against an code to determine if it falls into the - * Server Error message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. - * - * @param code - * the code to test. - * @return true if within range of codes that belongs to - * Server Error messages. - */ - public static boolean isServerError(int code) - { - return ((500 <= code) && (code <= 599)); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpTokens.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpTokens.java deleted file mode 100644 index 66aabdaf727..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpTokens.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -/** - * HTTP constants - */ -public interface HttpTokens -{ - // Terminal symbols. - static final byte COLON= (byte)':'; - static final byte TAB= 0x09; - static final byte LINE_FEED= 0x0A; - static final byte CARRIAGE_RETURN= 0x0D; - static final byte SPACE= 0x20; - static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED}; - static final byte SEMI_COLON= (byte)';'; - - public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT } - -} - diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpURI.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpURI.java deleted file mode 100644 index 87ce90cf426..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpURI.java +++ /dev/null @@ -1,783 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.URIUtil; -import org.eclipse.jetty.util.UrlEncoded; - - -/* ------------------------------------------------------------ */ -/** Http URI. - * Parse a HTTP URI from a string or byte array. Given a URI - * http://user@host:port/path/info;param?query#fragment - * this class will split it into the following undecoded optional elements:
    - *
  • {@link #getScheme()} - http:
  • - *
  • {@link #getAuthority()} - //name@host:port
  • - *
  • {@link #getHost()} - host
  • - *
  • {@link #getPort()} - port
  • - *
  • {@link #getPath()} - /path/info
  • - *
  • {@link #getParam()} - param
  • - *
  • {@link #getQuery()} - query
  • - *
  • {@link #getFragment()} - fragment
  • - *
- * - *

Any parameters will be returned from {@link #getPath()}, but are excluded from the - * return value of {@link #getDecodedPath()}. If there are multiple parameters, the - * {@link #getParam()} method returns only the last one. - */ -public class HttpURI -{ - private enum State { - START, - HOST_OR_PATH, - SCHEME_OR_PATH, - HOST, - IPV6, - PORT, - PATH, - PARAM, - QUERY, - FRAGMENT, - ASTERISK}; - - private String _scheme; - private String _user; - private String _host; - private int _port; - private String _path; - private String _param; - private String _query; - private String _fragment; - - String _uri; - String _decodedPath; - - /* ------------------------------------------------------------ */ - /** - * Construct a normalized URI. - * Port is not set if it is the default port. - * @param scheme the URI scheme - * @param host the URI hose - * @param port the URI port - * @param path the URI path - * @param param the URI param - * @param query the URI query - * @param fragment the URI fragment - * @return the normalized URI - */ - public static HttpURI createHttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) - { - if (port==80 && HttpScheme.HTTP.is(scheme)) - port=0; - if (port==443 && HttpScheme.HTTPS.is(scheme)) - port=0; - return new HttpURI(scheme,host,port,path,param,query,fragment); - } - - /* ------------------------------------------------------------ */ - public HttpURI() - { - } - - /* ------------------------------------------------------------ */ - public HttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) - { - _scheme = scheme; - _host = host; - _port = port; - _path = path; - _param = param; - _query = query; - _fragment = fragment; - } - - /* ------------------------------------------------------------ */ - public HttpURI(HttpURI uri) - { - this(uri._scheme,uri._host,uri._port,uri._path,uri._param,uri._query,uri._fragment); - } - - /* ------------------------------------------------------------ */ - public HttpURI(String uri) - { - _port=-1; - parse(State.START,uri,0,uri.length()); - } - - /* ------------------------------------------------------------ */ - public HttpURI(URI uri) - { - _uri=null; - - _scheme=uri.getScheme(); - _host=uri.getHost(); - if (_host==null && uri.getRawSchemeSpecificPart().startsWith("//")) - _host=""; - _port=uri.getPort(); - _user = uri.getUserInfo(); - _path=uri.getRawPath(); - - _decodedPath = uri.getPath(); - if (_decodedPath != null) - { - int p = _decodedPath.lastIndexOf(';'); - if (p >= 0) - _param = _decodedPath.substring(p + 1); - } - _query=uri.getRawQuery(); - _fragment=uri.getFragment(); - - _decodedPath=null; - } - - /* ------------------------------------------------------------ */ - public HttpURI(String scheme, String host, int port, String pathQuery) - { - _uri=null; - - _scheme=scheme; - _host=host; - _port=port; - - parse(State.PATH,pathQuery,0,pathQuery.length()); - - } - - /* ------------------------------------------------------------ */ - public void parse(String uri) - { - clear(); - _uri=uri; - parse(State.START,uri,0,uri.length()); - } - - /* ------------------------------------------------------------ */ - /** Parse according to https://tools.ietf.org/html/rfc7230#section-5.3 - * @param method - * @param uri - */ - public void parseRequestTarget(String method,String uri) - { - clear(); - _uri=uri; - - if (HttpMethod.CONNECT.is(method)) - _path=uri; - else - parse(uri.startsWith("/")?State.PATH:State.START,uri,0,uri.length()); - } - - /* ------------------------------------------------------------ */ - @Deprecated - public void parseConnect(String uri) - { - clear(); - _uri=uri; - _path=uri; - } - - /* ------------------------------------------------------------ */ - public void parse(String uri, int offset, int length) - { - clear(); - int end=offset+length; - _uri=uri.substring(offset,end); - parse(State.START,uri,offset,end); - } - - /* ------------------------------------------------------------ */ - private void parse(State state, final String uri, final int offset, final int end) - { - boolean encoded=false; - int mark=offset; - int path_mark=0; - - for (int i=offset; i mark) - _host=uri.substring(mark,i); - mark=i+1; - state=State.PORT; - break; - case '@': - if (_user!=null) - throw new IllegalArgumentException("Bad authority"); - _user=uri.substring(mark,i); - mark=i+1; - break; - - case '[': - state=State.IPV6; - break; - } - continue; - } - - case IPV6: - { - switch (c) - { - case '/': - throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); - case ']': - c = uri.charAt(++i); - _host=uri.substring(mark,i); - if (c == ':') - { - mark=i+1; - state=State.PORT; - } - else - { - path_mark=mark=i; - state=State.PATH; - } - break; - } - - continue; - } - - case PORT: - { - if (c=='@') - { - if (_user!=null) - throw new IllegalArgumentException("Bad authority"); - // It wasn't a port, but a password! - _user=_host+":"+uri.substring(mark,i); - mark=i+1; - state=State.HOST; - } - else if (c=='/') - { - _port=TypeUtil.parseInt(uri,mark,i-mark,10); - path_mark=mark=i; - state=State.PATH; - } - continue; - } - - case PATH: - { - switch (c) - { - case ';': - mark=i+1; - state=State.PARAM; - break; - case '?': - _path=uri.substring(path_mark,i); - mark=i+1; - state=State.QUERY; - break; - case '#': - _path=uri.substring(path_mark,i); - mark=i+1; - state=State.FRAGMENT; - break; - case '%': - encoded=true; - break; - } - continue; - } - - case PARAM: - { - switch (c) - { - case '?': - _path=uri.substring(path_mark,i); - _param=uri.substring(mark,i); - mark=i+1; - state=State.QUERY; - break; - case '#': - _path=uri.substring(path_mark,i); - _param=uri.substring(mark,i); - mark=i+1; - state=State.FRAGMENT; - break; - case '/': - encoded=true; - // ignore internal params - state=State.PATH; - break; - case ';': - // multiple parameters - mark=i+1; - break; - } - continue; - } - - case QUERY: - { - if (c=='#') - { - _query=uri.substring(mark,i); - mark=i+1; - state=State.FRAGMENT; - } - continue; - } - - case ASTERISK: - { - throw new IllegalArgumentException("only '*'"); - } - - case FRAGMENT: - { - _fragment=uri.substring(mark,end); - i=end; - } - } - } - - - switch(state) - { - case START: - break; - case SCHEME_OR_PATH: - _path=uri.substring(mark,end); - break; - - case HOST_OR_PATH: - _path=uri.substring(mark,end); - break; - - case HOST: - if(end>mark) - _host=uri.substring(mark,end); - break; - - case IPV6: - throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); - - case PORT: - _port=TypeUtil.parseInt(uri,mark,end-mark,10); - break; - - case ASTERISK: - break; - - case FRAGMENT: - _fragment=uri.substring(mark,end); - break; - - case PARAM: - _path=uri.substring(path_mark,end); - _param=uri.substring(mark,end); - break; - - case PATH: - _path=uri.substring(path_mark,end); - break; - - case QUERY: - _query=uri.substring(mark,end); - break; - } - - if (!encoded) - { - if (_param==null) - _decodedPath=_path; - else - _decodedPath=_path.substring(0,_path.length()-_param.length()-1); - } - } - - /* ------------------------------------------------------------ */ - public String getScheme() - { - return _scheme; - } - - /* ------------------------------------------------------------ */ - public String getHost() - { - // Return null for empty host to retain compatibility with java.net.URI - if (_host!=null && _host.length()==0) - return null; - return _host; - } - - /* ------------------------------------------------------------ */ - public int getPort() - { - return _port; - } - - /* ------------------------------------------------------------ */ - /** - * The parsed Path. - * - * @return the path as parsed on valid URI. null for invalid URI. - */ - public String getPath() - { - return _path; - } - - /* ------------------------------------------------------------ */ - public String getDecodedPath() - { - if (_decodedPath==null && _path!=null) - _decodedPath=URIUtil.decodePath(_path); - return _decodedPath; - } - - /* ------------------------------------------------------------ */ - public String getParam() - { - return _param; - } - - /* ------------------------------------------------------------ */ - public String getQuery() - { - return _query; - } - - /* ------------------------------------------------------------ */ - public boolean hasQuery() - { - return _query!=null && _query.length()>0; - } - - /* ------------------------------------------------------------ */ - public String getFragment() - { - return _fragment; - } - - /* ------------------------------------------------------------ */ - public void decodeQueryTo(MultiMap parameters) - { - if (_query==_fragment) - return; - UrlEncoded.decodeUtf8To(_query,parameters); - } - - /* ------------------------------------------------------------ */ - public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException - { - decodeQueryTo(parameters,Charset.forName(encoding)); - } - - /* ------------------------------------------------------------ */ - public void decodeQueryTo(MultiMap parameters, Charset encoding) throws UnsupportedEncodingException - { - if (_query==_fragment) - return; - - if (encoding==null || StandardCharsets.UTF_8.equals(encoding)) - UrlEncoded.decodeUtf8To(_query,parameters); - else - UrlEncoded.decodeTo(_query,parameters,encoding); - } - - /* ------------------------------------------------------------ */ - public void clear() - { - _uri=null; - - _scheme=null; - _host=null; - _port=-1; - _path=null; - _param=null; - _query=null; - _fragment=null; - - _decodedPath=null; - } - - /* ------------------------------------------------------------ */ - public boolean isAbsolute() - { - return _scheme!=null && _scheme.length()>0; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - if (_uri==null) - { - StringBuilder out = new StringBuilder(); - - if (_scheme!=null) - out.append(_scheme).append(':'); - - if (_host != null) - { - out.append("//"); - if (_user != null) - out.append(_user).append('@'); - out.append(_host); - } - - if (_port>0) - out.append(':').append(_port); - - if (_path!=null) - out.append(_path); - - if (_query!=null) - out.append('?').append(_query); - - if (_fragment!=null) - out.append('#').append(_fragment); - - if (out.length()>0) - _uri=out.toString(); - else - _uri=""; - } - return _uri; - } - - /* ------------------------------------------------------------ */ - public boolean equals(Object o) - { - if (o==this) - return true; - if (!(o instanceof HttpURI)) - return false; - return toString().equals(o.toString()); - } - - /* ------------------------------------------------------------ */ - public void setScheme(String scheme) - { - _scheme=scheme; - _uri=null; - } - - /* ------------------------------------------------------------ */ - /** - * @param host the host - * @param port the port - */ - public void setAuthority(String host, int port) - { - _host=host; - _port=port; - _uri=null; - } - - /* ------------------------------------------------------------ */ - /** - * @param path the path - */ - public void setPath(String path) - { - _uri=null; - _path=path; - _decodedPath=null; - } - - /* ------------------------------------------------------------ */ - public void setPathQuery(String path) - { - _uri=null; - _path=null; - _decodedPath=null; - _param=null; - _fragment=null; - if (path!=null) - parse(State.PATH,path,0,path.length()); - } - - /* ------------------------------------------------------------ */ - public void setQuery(String query) - { - _query=query; - _uri=null; - } - - /* ------------------------------------------------------------ */ - public URI toURI() throws URISyntaxException - { - return new URI(_scheme,null,_host,_port,_path,_query==null?null:UrlEncoded.decodeString(_query),_fragment); - } - - /* ------------------------------------------------------------ */ - public String getPathQuery() - { - if (_query==null) - return _path; - return _path+"?"+_query; - } - - /* ------------------------------------------------------------ */ - public String getAuthority() - { - if (_port>0) - return _host+":"+_port; - return _host; - } - - /* ------------------------------------------------------------ */ - public String getUser() - { - return _user; - } - - -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpVersion.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpVersion.java deleted file mode 100644 index ddedc274710..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/HttpVersion.java +++ /dev/null @@ -1,173 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.Trie; - - -/* ------------------------------------------------------------------------------- */ -public enum HttpVersion -{ - HTTP_0_9("HTTP/0.9",9), - HTTP_1_0("HTTP/1.0",10), - HTTP_1_1("HTTP/1.1",11), - HTTP_2("HTTP/2.0",20); - - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); - static - { - for (HttpVersion version : HttpVersion.values()) - CACHE.put(version.toString(),version); - } - - /* ------------------------------------------------------------ */ - /** - * Optimised lookup to find a Http Version and whitespace in a byte array. - * @param bytes Array containing ISO-8859-1 characters - * @param position The first valid index - * @param limit The first non valid index - * @return A HttpMethod if a match or null if no easy match. - */ - public static HttpVersion lookAheadGet(byte[] bytes, int position, int limit) - { - int length=limit-position; - if (length<9) - return null; - - if (bytes[position+4]=='/' && bytes[position+6]=='.' && Character.isWhitespace((char)bytes[position+8]) && - ((bytes[position]=='H' && bytes[position+1]=='T' && bytes[position+2]=='T' && bytes[position+3]=='P') || - (bytes[position]=='h' && bytes[position+1]=='t' && bytes[position+2]=='t' && bytes[position+3]=='p'))) - { - switch(bytes[position+5]) - { - case '1': - switch(bytes[position+7]) - { - case '0': - return HTTP_1_0; - case '1': - return HTTP_1_1; - } - break; - case '2': - switch(bytes[position+7]) - { - case '0': - return HTTP_2; - } - break; - } - } - - return null; - } - - /* ------------------------------------------------------------ */ - /** - * Optimised lookup to find a HTTP Version and trailing white space in a byte array. - * @param buffer buffer containing ISO-8859-1 characters - * @return A HttpVersion if a match or null if no easy match. - */ - public static HttpVersion lookAheadGet(ByteBuffer buffer) - { - if (buffer.hasArray()) - return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit()); - return null; - } - - - private final String _string; - private final byte[] _bytes; - private final ByteBuffer _buffer; - private final int _version; - - /* ------------------------------------------------------------ */ - HttpVersion(String s,int version) - { - _string=s; - _bytes=StringUtil.getBytes(s); - _buffer=ByteBuffer.wrap(_bytes); - _version=version; - } - - /* ------------------------------------------------------------ */ - public byte[] toBytes() - { - return _bytes; - } - - /* ------------------------------------------------------------ */ - public ByteBuffer toBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public int getVersion() - { - return _version; - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return _string.equalsIgnoreCase(s); - } - - /* ------------------------------------------------------------ */ - public String asString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return _string; - } - - /** - * Case insensitive fromString() conversion - * @param version the String to convert to enum constant - * @return the enum constant or null if version unknown - */ - public static HttpVersion fromString(String version) - { - return CACHE.get(version); - } - - /* ------------------------------------------------------------ */ - public static HttpVersion fromVersion(int version) - { - switch(version) - { - case 9: return HttpVersion.HTTP_0_9; - case 10: return HttpVersion.HTTP_1_0; - case 11: return HttpVersion.HTTP_1_1; - case 20: return HttpVersion.HTTP_2; - default: throw new IllegalArgumentException(); - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MetaData.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MetaData.java deleted file mode 100644 index 725870db92b..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MetaData.java +++ /dev/null @@ -1,298 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.Collections; -import java.util.Iterator; - -public class MetaData implements Iterable -{ - private HttpVersion _httpVersion; - private HttpFields _fields; - private long _contentLength; - - public MetaData(HttpVersion version, HttpFields fields) - { - this(version, fields, Long.MIN_VALUE); - } - - public MetaData(HttpVersion version, HttpFields fields, long contentLength) - { - _httpVersion = version; - _fields = fields; - _contentLength = contentLength; - } - - protected void recycle() - { - _httpVersion = null; - if (_fields != null) - _fields.clear(); - _contentLength = Long.MIN_VALUE; - } - - public boolean isRequest() - { - return false; - } - - public boolean isResponse() - { - return false; - } - - /** - * @return the HTTP version of this MetaData object - */ - public HttpVersion getVersion() - { - return _httpVersion; - } - - /** - * @param httpVersion the HTTP version to set - */ - public void setHttpVersion(HttpVersion httpVersion) - { - _httpVersion = httpVersion; - } - - /** - * @return the HTTP fields of this MetaData object - */ - public HttpFields getFields() - { - return _fields; - } - - /** - * @return the content length if available, otherwise {@link Long#MIN_VALUE} - */ - public long getContentLength() - { - if (_contentLength == Long.MIN_VALUE) - { - if (_fields != null) - { - HttpField field = _fields.getField(HttpHeader.CONTENT_LENGTH); - _contentLength = field == null ? -1 : field.getLongValue(); - } - } - return _contentLength; - } - - /** - * @return an iterator over the HTTP fields - * @see #getFields() - */ - public Iterator iterator() - { - HttpFields fields = getFields(); - return fields == null ? Collections.emptyIterator() : fields.iterator(); - } - - @Override - public String toString() - { - StringBuilder out = new StringBuilder(); - for (HttpField field : this) - out.append(field).append(System.lineSeparator()); - return out.toString(); - } - - public static class Request extends MetaData - { - private String _method; - private HttpURI _uri; - - public Request(HttpFields fields) - { - this(null, null, null, fields); - } - - public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields) - { - this(method, uri, version, fields, Long.MIN_VALUE); - } - - public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength) - { - super(version, fields, contentLength); - _method = method; - _uri = uri; - } - - public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields) - { - this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields); - } - - public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) - { - this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength); - } - - public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) - { - this(method, new HttpURI(scheme, hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength); - } - - public Request(Request request) - { - this(request.getMethod(),new HttpURI(request.getURI()), request.getVersion(), new HttpFields(request.getFields()), request.getContentLength()); - } - - // TODO MetaData should be immuttable!!! - public void recycle() - { - super.recycle(); - _method = null; - if (_uri != null) - _uri.clear(); - } - - @Override - public boolean isRequest() - { - return true; - } - - /** - * @return the HTTP method - */ - public String getMethod() - { - return _method; - } - - /** - * @param method the HTTP method to set - */ - public void setMethod(String method) - { - _method = method; - } - - /** - * @return the HTTP URI - */ - public HttpURI getURI() - { - return _uri; - } - - /** - * @return the HTTP URI in string form - */ - public String getURIString() - { - return _uri == null ? null : _uri.toString(); - } - - /** - * @param uri the HTTP URI to set - */ - public void setURI(HttpURI uri) - { - _uri = uri; - } - - @Override - public String toString() - { - HttpFields fields = getFields(); - return String.format("%s{u=%s,%s,h=%d}", - getMethod(), getURI(), getVersion(), fields == null ? -1 : fields.size()); - } - } - - public static class Response extends MetaData - { - private int _status; - private String _reason; - - public Response() - { - this(null, 0, null); - } - - public Response(HttpVersion version, int status, HttpFields fields) - { - this(version, status, fields, Long.MIN_VALUE); - } - - public Response(HttpVersion version, int status, HttpFields fields, long contentLength) - { - super(version, fields, contentLength); - _status = status; - } - - public Response(HttpVersion version, int status, String reason, HttpFields fields, long contentLength) - { - super(version, fields, contentLength); - _reason = reason; - _status = status; - } - - @Override - public boolean isResponse() - { - return true; - } - - /** - * @return the HTTP status - */ - public int getStatus() - { - return _status; - } - - /** - * @return the HTTP reason - */ - public String getReason() - { - return _reason; - } - - /** - * @param status the HTTP status to set - */ - public void setStatus(int status) - { - _status = status; - } - - /** - * @param reason the HTTP reason to set - */ - public void setReason(String reason) - { - _reason = reason; - } - - @Override - public String toString() - { - HttpFields fields = getFields(); - return String.format("%s{s=%d,h=%d}", getVersion(), getStatus(), fields == null ? -1 : fields.size()); - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MimeTypes.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MimeTypes.java deleted file mode 100644 index dbdd4b83c67..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/MimeTypes.java +++ /dev/null @@ -1,497 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.Set; - -import org.eclipse.jetty.util.ArrayTrie; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.Trie; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/* ------------------------------------------------------------ */ -/** - * - */ -public class MimeTypes -{ - public enum Type - { - FORM_ENCODED("application/x-www-form-urlencoded"), - MESSAGE_HTTP("message/http"), - MULTIPART_BYTERANGES("multipart/byteranges"), - - TEXT_HTML("text/html"), - TEXT_PLAIN("text/plain"), - TEXT_XML("text/xml"), - TEXT_JSON("text/json",StandardCharsets.UTF_8), - APPLICATION_JSON("application/json",StandardCharsets.UTF_8), - - TEXT_HTML_8859_1("text/html;charset=iso-8859-1",TEXT_HTML), - TEXT_HTML_UTF_8("text/html;charset=utf-8",TEXT_HTML), - - TEXT_PLAIN_8859_1("text/plain;charset=iso-8859-1",TEXT_PLAIN), - TEXT_PLAIN_UTF_8("text/plain;charset=utf-8",TEXT_PLAIN), - - TEXT_XML_8859_1("text/xml;charset=iso-8859-1",TEXT_XML), - TEXT_XML_UTF_8("text/xml;charset=utf-8",TEXT_XML), - - TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON), - TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON), - - APPLICATION_JSON_8859_1("text/json;charset=iso-8859-1",APPLICATION_JSON), - APPLICATION_JSON_UTF_8("text/json;charset=utf-8",APPLICATION_JSON); - - - /* ------------------------------------------------------------ */ - private final String _string; - private final Type _base; - private final ByteBuffer _buffer; - private final Charset _charset; - private final String _charsetString; - private final boolean _assumedCharset; - private final HttpField _field; - - /* ------------------------------------------------------------ */ - Type(String s) - { - _string=s; - _buffer=BufferUtil.toBuffer(s); - _base=this; - _charset=null; - _charsetString=null; - _assumedCharset=false; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); - } - - /* ------------------------------------------------------------ */ - Type(String s,Type base) - { - _string=s; - _buffer=BufferUtil.toBuffer(s); - _base=base; - int i=s.indexOf(";charset="); - _charset=Charset.forName(s.substring(i+9)); - _charsetString=_charset.toString().toLowerCase(Locale.ENGLISH); - _assumedCharset=false; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); - } - - /* ------------------------------------------------------------ */ - Type(String s,Charset cs) - { - _string=s; - _base=this; - _buffer=BufferUtil.toBuffer(s); - _charset=cs; - _charsetString=_charset==null?null:_charset.toString().toLowerCase(Locale.ENGLISH); - _assumedCharset=true; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); - } - - /* ------------------------------------------------------------ */ - public ByteBuffer asBuffer() - { - return _buffer.asReadOnlyBuffer(); - } - - /* ------------------------------------------------------------ */ - public Charset getCharset() - { - return _charset; - } - - /* ------------------------------------------------------------ */ - public String getCharsetString() - { - return _charsetString; - } - - /* ------------------------------------------------------------ */ - public boolean is(String s) - { - return _string.equalsIgnoreCase(s); - } - - /* ------------------------------------------------------------ */ - public String asString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return _string; - } - - /* ------------------------------------------------------------ */ - public boolean isCharsetAssumed() - { - return _assumedCharset; - } - - /* ------------------------------------------------------------ */ - public HttpField getContentTypeField() - { - return _field; - } - - /* ------------------------------------------------------------ */ - public Type getBaseType() - { - return _base; - } - } - - /* ------------------------------------------------------------ */ - private static final Logger LOG = Log.getLogger(MimeTypes.class); - public final static Trie CACHE= new ArrayTrie<>(512); - private final static Trie TYPES= new ArrayTrie(512); - private final static Map __dftMimeMap = new HashMap(); - private final static Map __encodings = new HashMap(); - - static - { - for (MimeTypes.Type type : MimeTypes.Type.values()) - { - CACHE.put(type.toString(),type); - TYPES.put(type.toString(),type.asBuffer()); - - int charset=type.toString().indexOf(";charset="); - if (charset>0) - { - String alt=type.toString().replace(";charset=","; charset="); - CACHE.put(alt,type); - TYPES.put(alt,type.asBuffer()); - } - } - - try - { - ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime"); - Enumeration i = mime.getKeys(); - while(i.hasMoreElements()) - { - String ext = i.nextElement(); - String m = mime.getString(ext); - __dftMimeMap.put(StringUtil.asciiToLowerCase(ext),normalizeMimeType(m)); - } - } - catch(MissingResourceException e) - { - LOG.warn(e.toString()); - LOG.debug(e); - } - - try - { - ResourceBundle encoding = ResourceBundle.getBundle("org/eclipse/jetty/http/encoding"); - Enumeration i = encoding.getKeys(); - while(i.hasMoreElements()) - { - String type = i.nextElement(); - __encodings.put(type,encoding.getString(type)); - } - } - catch(MissingResourceException e) - { - LOG.warn(e.toString()); - LOG.debug(e); - } - } - - - /* ------------------------------------------------------------ */ - private final Map _mimeMap=new HashMap(); - - /* ------------------------------------------------------------ */ - /** Constructor. - */ - public MimeTypes() - { - } - - /* ------------------------------------------------------------ */ - public synchronized Map getMimeMap() - { - return _mimeMap; - } - - /* ------------------------------------------------------------ */ - /** - * @param mimeMap A Map of file extension to mime-type. - */ - public void setMimeMap(Map mimeMap) - { - _mimeMap.clear(); - if (mimeMap!=null) - { - for (Entry ext : mimeMap.entrySet()) - _mimeMap.put(StringUtil.asciiToLowerCase(ext.getKey()),normalizeMimeType(ext.getValue())); - } - } - - /* ------------------------------------------------------------ */ - /** Get the MIME type by filename extension. - * @param filename A file name - * @return MIME type matching the longest dot extension of the - * file name. - */ - public String getMimeByExtension(String filename) - { - String type=null; - - if (filename!=null) - { - int i=-1; - while(type==null) - { - i=filename.indexOf(".",i+1); - - if (i<0 || i>=filename.length()) - break; - - String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); - if (_mimeMap!=null) - type=_mimeMap.get(ext); - if (type==null) - type=__dftMimeMap.get(ext); - } - } - - if (type==null) - { - if (_mimeMap!=null) - type=_mimeMap.get("*"); - if (type==null) - type=__dftMimeMap.get("*"); - } - - return type; - } - - /* ------------------------------------------------------------ */ - /** Set a mime mapping - * @param extension the extension - * @param type the mime type - */ - public void addMimeMapping(String extension,String type) - { - _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type)); - } - - /* ------------------------------------------------------------ */ - public static Set getKnownMimeTypes() - { - return new HashSet<>(__dftMimeMap.values()); - } - - /* ------------------------------------------------------------ */ - private static String normalizeMimeType(String type) - { - MimeTypes.Type t =CACHE.get(type); - if (t!=null) - return t.asString(); - - return StringUtil.asciiToLowerCase(type); - } - - /* ------------------------------------------------------------ */ - public static String getCharsetFromContentType(String value) - { - if (value==null) - return null; - int end=value.length(); - int state=0; - int start=0; - boolean quote=false; - int i=0; - for (;i - * This mapping implements the path specification recommended - * in the 2.2 Servlet API. - *

- * - *

- * Path specifications can be of the following forms: - *

- *
- * /foo/bar           - an exact path specification.
- * /foo/*             - a prefix path specification (must end '/*').
- * *.ext              - a suffix path specification.
- * /                  - the default path specification.
- * ""                 - the / path specification
- * 
- * - * Matching is performed in the following order - *
    - *
  1. Exact match.
  2. - *
  3. Longest prefix match.
  4. - *
  5. Longest suffix match.
  6. - *
  7. default.
  8. - *
- * - *

- * Multiple path specifications can be mapped by providing a list of - * specifications. By default this class uses characters ":," as path - * separators, unless configured differently by calling the static - * method @see PathMap#setPathSpecSeparators(String) - *

- * Special characters within paths such as '?� and ';' are not treated specially - * as it is assumed they would have been either encoded in the original URL or - * stripped from the path. - *

- * This class is not synchronized. If concurrent modifications are - * possible then it should be synchronized at a higher level. - * - * @param the Map.Entry value type - * @deprecated replaced with {@link org.eclipse.jetty.http.pathmap.PathMappings} (this class will be removed in Jetty 10) - */ -@Deprecated -public class PathMap extends HashMap -{ - /* ------------------------------------------------------------ */ - private static String __pathSpecSeparators = ":,"; - - /* ------------------------------------------------------------ */ - /** Set the path spec separator. - * Multiple path specification may be included in a single string - * if they are separated by the characters set in this string. - * By default this class uses ":," characters as path separators. - * @param s separators - */ - public static void setPathSpecSeparators(String s) - { - __pathSpecSeparators=s; - } - - /* --------------------------------------------------------------- */ - Trie> _prefixMap=new ArrayTernaryTrie<>(false); - Trie> _suffixMap=new ArrayTernaryTrie<>(false); - final Map> _exactMap=new HashMap<>(); - - List> _defaultSingletonList=null; - MappedEntry _prefixDefault=null; - MappedEntry _default=null; - boolean _nodefault=false; - - /* --------------------------------------------------------------- */ - public PathMap() - { - this(11); - } - - /* --------------------------------------------------------------- */ - public PathMap(boolean noDefault) - { - this(11, noDefault); - } - - /* --------------------------------------------------------------- */ - public PathMap(int capacity) - { - this(capacity, false); - } - - /* --------------------------------------------------------------- */ - private PathMap(int capacity, boolean noDefault) - { - super(capacity); - _nodefault=noDefault; - } - - /* --------------------------------------------------------------- */ - /** - * Construct from dictionary PathMap. - * @param dictMap the map representing the dictionary to build this PathMap from - */ - public PathMap(Map dictMap) - { - putAll(dictMap); - } - - /* --------------------------------------------------------------- */ - /** Add a single path match to the PathMap. - * @param pathSpec The path specification, or comma separated list of - * path specifications. - * @param object The object the path maps to - */ - @Override - public O put(String pathSpec, O object) - { - if ("".equals(pathSpec.trim())) - { - MappedEntry entry = new MappedEntry<>("",object); - entry.setMapped(""); - _exactMap.put("", entry); - return super.put("", object); - } - - StringTokenizer tok = new StringTokenizer(pathSpec,__pathSpecSeparators); - O old =null; - - while (tok.hasMoreTokens()) - { - String spec=tok.nextToken(); - - if (!spec.startsWith("/") && !spec.startsWith("*.")) - throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'"); - - old = super.put(spec,object); - - // Make entry that was just created. - MappedEntry entry = new MappedEntry<>(spec,object); - - if (entry.getKey().equals(spec)) - { - if (spec.equals("/*")) - _prefixDefault=entry; - else if (spec.endsWith("/*")) - { - String mapped=spec.substring(0,spec.length()-2); - entry.setMapped(mapped); - while (!_prefixMap.put(mapped,entry)) - _prefixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap,1.5); - } - else if (spec.startsWith("*.")) - { - String suffix=spec.substring(2); - while(!_suffixMap.put(suffix,entry)) - _suffixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_suffixMap,1.5); - } - else if (spec.equals(URIUtil.SLASH)) - { - if (_nodefault) - _exactMap.put(spec,entry); - else - { - _default=entry; - _defaultSingletonList=Collections.singletonList(_default); - } - } - else - { - entry.setMapped(spec); - _exactMap.put(spec,entry); - } - } - } - - return old; - } - - /* ------------------------------------------------------------ */ - /** Get object matched by the path. - * @param path the path. - * @return Best matched object or null. - */ - public O match(String path) - { - MappedEntry entry = getMatch(path); - if (entry!=null) - return entry.getValue(); - return null; - } - - - /* --------------------------------------------------------------- */ - /** Get the entry mapped by the best specification. - * @param path the path. - * @return Map.Entry of the best matched or null. - */ - public MappedEntry getMatch(String path) - { - if (path==null) - return null; - - int l=path.length(); - - MappedEntry entry=null; - - //special case - if (l == 1 && path.charAt(0)=='/') - { - entry = _exactMap.get(""); - if (entry != null) - return entry; - } - - // try exact match - entry=_exactMap.get(path); - if (entry!=null) - return entry; - - // prefix search - int i=l; - final Trie> prefix_map=_prefixMap; - while(i>=0) - { - entry=prefix_map.getBest(path,0,i); - if (entry==null) - break; - String key = entry.getKey(); - if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/') - return entry; - i=key.length()-3; - } - - // Prefix Default - if (_prefixDefault!=null) - return _prefixDefault; - - // Extension search - i=0; - final Trie> suffix_map=_suffixMap; - while ((i=path.indexOf('.',i+1))>0) - { - entry=suffix_map.get(path,i+1,l-i-1); - if (entry!=null) - return entry; - } - - // Default - return _default; - } - - /* --------------------------------------------------------------- */ - /** Get all entries matched by the path. - * Best match first. - * @param path Path to match - * @return List of Map.Entry instances key=pathSpec - */ - public List> getMatches(String path) - { - MappedEntry entry; - List> entries=new ArrayList<>(); - - if (path==null) - return entries; - if (path.length()==0) - return _defaultSingletonList; - - // try exact match - entry=_exactMap.get(path); - if (entry!=null) - entries.add(entry); - - // prefix search - int l=path.length(); - int i=l; - final Trie> prefix_map=_prefixMap; - while(i>=0) - { - entry=prefix_map.getBest(path,0,i); - if (entry==null) - break; - String key = entry.getKey(); - if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/') - entries.add(entry); - - i=key.length()-3; - } - - // Prefix Default - if (_prefixDefault!=null) - entries.add(_prefixDefault); - - // Extension search - i=0; - final Trie> suffix_map=_suffixMap; - while ((i=path.indexOf('.',i+1))>0) - { - entry=suffix_map.get(path,i+1,l-i-1); - if (entry!=null) - entries.add(entry); - } - - // root match - if ("/".equals(path)) - { - entry=_exactMap.get(""); - if (entry!=null) - entries.add(entry); - } - - // Default - if (_default!=null) - entries.add(_default); - - return entries; - } - - - /* --------------------------------------------------------------- */ - /** Return whether the path matches any entries in the PathMap, - * excluding the default entry - * @param path Path to match - * @return Whether the PathMap contains any entries that match this - */ - public boolean containsMatch(String path) - { - MappedEntry match = getMatch(path); - return match!=null && !match.equals(_default); - } - - /* --------------------------------------------------------------- */ - @Override - public O remove(Object pathSpec) - { - if (pathSpec!=null) - { - String spec=(String) pathSpec; - if (spec.equals("/*")) - _prefixDefault=null; - else if (spec.endsWith("/*")) - _prefixMap.remove(spec.substring(0,spec.length()-2)); - else if (spec.startsWith("*.")) - _suffixMap.remove(spec.substring(2)); - else if (spec.equals(URIUtil.SLASH)) - { - _default=null; - _defaultSingletonList=null; - } - else - _exactMap.remove(spec); - } - return super.remove(pathSpec); - } - - /* --------------------------------------------------------------- */ - @Override - public void clear() - { - _exactMap.clear(); - _prefixMap=new ArrayTernaryTrie<>(false); - _suffixMap=new ArrayTernaryTrie<>(false); - _default=null; - _defaultSingletonList=null; - _prefixDefault=null; - super.clear(); - } - - /* --------------------------------------------------------------- */ - /** - * @param pathSpec the path spec - * @param path the path - * @return true if match. - */ - public static boolean match(String pathSpec, String path) - { - return match(pathSpec, path, false); - } - - /* --------------------------------------------------------------- */ - /** - * @param pathSpec the path spec - * @param path the path - * @param noDefault true to not handle the default path "/" special, false to allow matcher rules to run - * @return true if match. - */ - public static boolean match(String pathSpec, String path, boolean noDefault) - { - if (pathSpec.length()==0) - return "/".equals(path); - - char c = pathSpec.charAt(0); - if (c=='/') - { - if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path)) - return true; - - if(isPathWildcardMatch(pathSpec, path)) - return true; - } - else if (c=='*') - return path.regionMatches(path.length()-pathSpec.length()+1, - pathSpec,1,pathSpec.length()-1); - return false; - } - - /* --------------------------------------------------------------- */ - private static boolean isPathWildcardMatch(String pathSpec, String path) - { - // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar" - int cpl=pathSpec.length()-2; - if (pathSpec.endsWith("/*") && path.regionMatches(0,pathSpec,0,cpl)) - { - if (path.length()==cpl || '/'==path.charAt(cpl)) - return true; - } - return false; - } - - - /* --------------------------------------------------------------- */ - /** Return the portion of a path that matches a path spec. - * @param pathSpec the path spec - * @param path the path - * @return null if no match at all. - */ - public static String pathMatch(String pathSpec, String path) - { - char c = pathSpec.charAt(0); - - if (c=='/') - { - if (pathSpec.length()==1) - return path; - - if (pathSpec.equals(path)) - return path; - - if (isPathWildcardMatch(pathSpec, path)) - return path.substring(0,pathSpec.length()-2); - } - else if (c=='*') - { - if (path.regionMatches(path.length()-(pathSpec.length()-1), - pathSpec,1,pathSpec.length()-1)) - return path; - } - return null; - } - - /* --------------------------------------------------------------- */ - /** Return the portion of a path that is after a path spec. - * @param pathSpec the path spec - * @param path the path - * @return The path info string - */ - public static String pathInfo(String pathSpec, String path) - { - if ("".equals(pathSpec)) - return path; //servlet 3 spec sec 12.2 will be '/' - - char c = pathSpec.charAt(0); - - if (c=='/') - { - if (pathSpec.length()==1) - return null; - - boolean wildcard = isPathWildcardMatch(pathSpec, path); - - // handle the case where pathSpec uses a wildcard and path info is "/*" - if (pathSpec.equals(path) && !wildcard) - return null; - - if (wildcard) - { - if (path.length()==pathSpec.length()-2) - return null; - return path.substring(pathSpec.length()-2); - } - } - return null; - } - - - /* ------------------------------------------------------------ */ - /** Relative path. - * @param base The base the path is relative to. - * @param pathSpec The spec of the path segment to ignore. - * @param path the additional path - * @return base plus path with pathspec removed - */ - public static String relativePath(String base, - String pathSpec, - String path ) - { - String info=pathInfo(pathSpec,path); - if (info==null) - info=path; - - if( info.startsWith( "./")) - info = info.substring( 2); - if( base.endsWith( URIUtil.SLASH)) - if( info.startsWith( URIUtil.SLASH)) - path = base + info.substring(1); - else - path = base + info; - else - if( info.startsWith( URIUtil.SLASH)) - path = base + info; - else - path = base + URIUtil.SLASH + info; - return path; - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static class MappedEntry implements Map.Entry - { - private final String key; - private final O value; - private String mapped; - - MappedEntry(String key, O value) - { - this.key=key; - this.value=value; - } - - @Override - public String getKey() - { - return key; - } - - @Override - public O getValue() - { - return value; - } - - @Override - public O setValue(O o) - { - throw new UnsupportedOperationException(); - } - - @Override - public String toString() - { - return key+"="+value; - } - - public String getMapped() - { - return mapped; - } - - void setMapped(String mapped) - { - this.mapped = mapped; - } - } - - public static class PathSet extends AbstractSet implements Predicate - { - private final PathMap _map = new PathMap<>(); - - @Override - public Iterator iterator() - { - return _map.keySet().iterator(); - } - - @Override - public int size() - { - return _map.size(); - } - - @Override - public boolean add(String item) - { - return _map.put(item,Boolean.TRUE)==null; - } - - @Override - public boolean remove(Object item) - { - return _map.remove(item)!=null; - } - - @Override - public boolean contains(Object o) - { - return _map.containsKey(o); - } - - @Override - public boolean test(String s) - { - return _map.containsMatch(s); - } - - public boolean containsMatch(String s) - { - return _map.containsMatch(s); - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/PreEncodedHttpField.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/PreEncodedHttpField.java deleted file mode 100644 index 6c81a914693..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/PreEncodedHttpField.java +++ /dev/null @@ -1,94 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/* ------------------------------------------------------------ */ -/** Pre encoded HttpField. - *

A HttpField that will be cached and used many times can be created as - * a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder} - * instances discovered by the {@link ServiceLoader} to pre-encode the header - * for each version of HTTP in use. This will save garbage - * and CPU each time the field is encoded into a response. - *

- */ -public class PreEncodedHttpField extends HttpField -{ - private final static Logger LOG = Log.getLogger(PreEncodedHttpField.class); - private final static HttpFieldPreEncoder[] __encoders; - - static - { - List encoders = new ArrayList<>(); - Iterator iter = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader()).iterator(); - while (iter.hasNext()) - { - try - { - encoders.add(iter.next()); - } - catch(Error|RuntimeException e) - { - LOG.debug(e); - } - } - // TODO avoid needing this catch all - if (encoders.size()==0) - encoders.add(new Http1FieldPreEncoder()); - LOG.debug("HttpField encoders loaded: {}",encoders); - __encoders = encoders.toArray(new HttpFieldPreEncoder[encoders.size()]); - } - - private final byte[][] _encodedField=new byte[2][]; - - public PreEncodedHttpField(HttpHeader header,String name,String value) - { - super(header,name, value); - - for (HttpFieldPreEncoder e:__encoders) - { - _encodedField[e.getHttpVersion()==HttpVersion.HTTP_2?1:0]=e.getEncodedField(header,header.asString(),value); - } - } - - public PreEncodedHttpField(HttpHeader header,String value) - { - this(header,header.asString(),value); - } - - public PreEncodedHttpField(String name,String value) - { - this(null,name,value); - } - - public void putTo(ByteBuffer bufferInFillMode, HttpVersion version) - { - bufferInFillMode.put(_encodedField[version==HttpVersion.HTTP_2?1:0]); - } -} \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/QuotedCSV.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/QuotedCSV.java deleted file mode 100644 index 8c9a779c415..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/QuotedCSV.java +++ /dev/null @@ -1,229 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/* ------------------------------------------------------------ */ -/** - * Implements a quoted comma separated list of values - * in accordance with RFC7230. - * OWS is removed and quoted characters ignored for parsing. - * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6" - * @see "https://tools.ietf.org/html/rfc7230#section-7" - */ -public class QuotedCSV implements Iterable -{ - private enum State { VALUE, PARAM_NAME, PARAM_VALUE}; - - private final List _values = new ArrayList<>(); - private final boolean _keepQuotes; - - /* ------------------------------------------------------------ */ - public QuotedCSV(String... values) - { - this(true,values); - } - - /* ------------------------------------------------------------ */ - public QuotedCSV(boolean keepQuotes,String... values) - { - _keepQuotes=keepQuotes; - for (String v:values) - addValue(v); - } - - /* ------------------------------------------------------------ */ - public void addValue(String value) - { - StringBuffer buffer = new StringBuffer(); - - int l=value.length(); - State state=State.VALUE; - boolean quoted=false; - boolean sloshed=false; - int nws_length=0; - int last_length=0; - for (int i=0;i<=l;i++) - { - char c=i==l?0:value.charAt(i); - - // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6 - if (quoted && c!=0) - { - if (sloshed) - sloshed=false; - else - { - switch(c) - { - case '\\': - sloshed=true; - if (!_keepQuotes) - continue; - break; - case '"': - quoted=false; - if (!_keepQuotes) - continue; - break; - } - } - - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - // Handle common cases - switch(c) - { - case ' ': - case '\t': - if (buffer.length()>last_length) // not leading OWS - buffer.append(c); - continue; - - case '"': - quoted=true; - if (_keepQuotes) - buffer.append(c); - nws_length=buffer.length(); - continue; - - case ';': - buffer.setLength(nws_length); // trim following OWS - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_NAME; - continue; - - case ',': - case 0: - if (nws_length>0) - { - buffer.setLength(nws_length); // trim following OWS - _values.add(buffer.toString()); - } - buffer.setLength(0); - last_length=0; - nws_length=0; - state=State.VALUE; - continue; - - default: - { - switch (state) - { - case VALUE: - { - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - case PARAM_NAME: - { - if (c=='=') - { - buffer.setLength(nws_length); // trim following OWS - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_VALUE; - continue; - } - buffer.append(c); - nws_length=buffer.length(); - - continue; - } - - case PARAM_VALUE: - { - buffer.append(c); - nws_length=buffer.length(); - continue; - } - } - } - } - } - } - - public List getValues() - { - return _values; - } - - @Override - public Iterator iterator() - { - return _values.iterator(); - } - - public static String unquote(String s) - { - // handle trivial cases - int l=s.length(); - if (s==null || l==0) - return s; - - // Look for any quotes - int i=0; - for (;i -{ - private final static Double ZERO=new Double(0.0); - private final static Double ONE=new Double(1.0); - private enum State { VALUE, PARAM_NAME, PARAM_VALUE, Q_VALUE}; - - private final List _values = new ArrayList<>(); - private final List _quality = new ArrayList<>(); - private boolean _sorted = false; - - /* ------------------------------------------------------------ */ - public QuotedQualityCSV(String... values) - { - for (String v:values) - addValue(v); - } - - - /* ------------------------------------------------------------ */ - public void addValue(String value) - { - StringBuffer buffer = new StringBuffer(); - - int l=value.length(); - State state=State.VALUE; - boolean quoted=false; - boolean sloshed=false; - int nws_length=0; - int last_length=0; - Double q=ONE; - for (int i=0;i<=l;i++) - { - char c=i==l?0:value.charAt(i); - - // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6 - if (quoted && c!=0) - { - if (sloshed) - sloshed=false; - else - { - switch(c) - { - case '\\': - sloshed=true; - break; - case '"': - quoted=false; - if (state==State.Q_VALUE) - continue; - break; - } - } - - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - // Handle common cases - switch(c) - { - case ' ': - case '\t': - if (buffer.length()>last_length) // not leading OWS - buffer.append(c); - continue; - - case '"': - quoted=true; - if (state==State.Q_VALUE) - continue; - - buffer.append(c); - nws_length=buffer.length(); - continue; - - case ';': - if (state==State.Q_VALUE) - { - try - { - q=new Double(buffer.substring(last_length)); - } - catch(Exception e) - { - q=ZERO; - } - nws_length=last_length; - } - - buffer.setLength(nws_length); // trim following OWS - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_NAME; - continue; - - case ',': - case 0: - if (state==State.Q_VALUE) - { - try - { - q=new Double(buffer.substring(last_length)); - } - catch(Exception e) - { - q=ZERO; - } - nws_length=last_length; - } - buffer.setLength(nws_length); // trim following OWS - if (q>0.0 && nws_length>0) - { - _values.add(buffer.toString()); - _quality.add(q); - _sorted=false; - } - buffer.setLength(0); - last_length=0; - nws_length=0; - q=ONE; - state=State.VALUE; - continue; - - default: - { - switch (state) - { - case VALUE: - { - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - case PARAM_NAME: - { - if (c=='=') - { - buffer.setLength(nws_length); // trim following OWS - if (nws_length-last_length==1 && Character.toLowerCase(buffer.charAt(last_length))=='q') - { - buffer.setLength(last_length-1); - nws_length=buffer.length(); - last_length=nws_length; - state=State.Q_VALUE; - continue; - } - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_VALUE; - continue; - } - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - case PARAM_VALUE: - case Q_VALUE: - { - buffer.append(c); - nws_length=buffer.length(); - continue; - } - } - } - } - } - } - - public List getValues() - { - if (!_sorted) - sort(); - return _values; - } - - @Override - public Iterator iterator() - { - if (!_sorted) - sort(); - return _values.iterator(); - } - - protected void sort() - { - _sorted=true; - - Double last = ZERO; - int len = Integer.MIN_VALUE; - - for (int i = _values.size(); i-- > 0;) - { - String v = _values.get(i); - Double q = _quality.get(i); - - int compare=last.compareTo(q); - if (compare > 0 || (compare==0 && v.length()The HttpContent is used to server static content that is not - * cached. So fields and values are only generated as need be an not - * kept for reuse

- */ -public class ResourceHttpContent implements HttpContent -{ - final Resource _resource; - final String _contentType; - final int _maxBuffer; - HttpContent _gzip; - String _etag; - - /* ------------------------------------------------------------ */ - public ResourceHttpContent(final Resource resource, final String contentType) - { - this(resource,contentType,-1,null); - } - - /* ------------------------------------------------------------ */ - public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer) - { - this(resource,contentType,maxBuffer,null); - } - - /* ------------------------------------------------------------ */ - public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer, HttpContent gzip) - { - _resource=resource; - _contentType=contentType; - _maxBuffer=maxBuffer; - _gzip=gzip; - } - - /* ------------------------------------------------------------ */ - @Override - public String getContentTypeValue() - { - return _contentType; - } - - /* ------------------------------------------------------------ */ - @Override - public HttpField getContentType() - { - return _contentType==null?null:new HttpField(HttpHeader.CONTENT_TYPE,_contentType); - } - - /* ------------------------------------------------------------ */ - @Override - public HttpField getContentEncoding() - { - return null; - } - - /* ------------------------------------------------------------ */ - @Override - public String getContentEncodingValue() - { - return null; - } - - /* ------------------------------------------------------------ */ - @Override - public String getCharacterEncoding() - { - return _contentType==null?null:MimeTypes.getCharsetFromContentType(_contentType); - } - - /* ------------------------------------------------------------ */ - @Override - public Type getMimeType() - { - return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType)); - } - - /* ------------------------------------------------------------ */ - @Override - public HttpField getLastModified() - { - long lm = _resource.lastModified(); - return lm>=0?new HttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(lm)):null; - } - - /* ------------------------------------------------------------ */ - @Override - public String getLastModifiedValue() - { - long lm = _resource.lastModified(); - return lm>=0?DateGenerator.formatDate(lm):null; - } - - /* ------------------------------------------------------------ */ - @Override - public ByteBuffer getDirectBuffer() - { - if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length()) - return null; - try - { - return BufferUtil.toBuffer(_resource,true); - } - catch(IOException e) - { - throw new RuntimeException(e); - } - } - - /* ------------------------------------------------------------ */ - @Override - public HttpField getETag() - { - return new HttpField(HttpHeader.ETAG,getETagValue()); - } - - /* ------------------------------------------------------------ */ - @Override - public String getETagValue() - { - return _resource.getWeakETag(); - } - - /* ------------------------------------------------------------ */ - @Override - public ByteBuffer getIndirectBuffer() - { - if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length()) - return null; - try - { - return BufferUtil.toBuffer(_resource,false); - } - catch(IOException e) - { - throw new RuntimeException(e); - } - } - - /* ------------------------------------------------------------ */ - @Override - public HttpField getContentLength() - { - long l=_resource.length(); - return l==-1?null:new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,_resource.length()); - } - - /* ------------------------------------------------------------ */ - @Override - public long getContentLengthValue() - { - return _resource.length(); - } - - /* ------------------------------------------------------------ */ - @Override - public InputStream getInputStream() throws IOException - { - return _resource.getInputStream(); - } - - /* ------------------------------------------------------------ */ - @Override - public ReadableByteChannel getReadableByteChannel() throws IOException - { - return _resource.getReadableByteChannel(); - } - - /* ------------------------------------------------------------ */ - @Override - public Resource getResource() - { - return _resource; - } - - /* ------------------------------------------------------------ */ - @Override - public void release() - { - _resource.close(); - } - - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - return String.format("%s@%x{r=%s,gz=%b}",this.getClass().getSimpleName(),hashCode(),_resource,_gzip!=null); - } - - /* ------------------------------------------------------------ */ - @Override - public HttpContent getGzipContent() - { - return _gzip==null?null:new GzipHttpContent(this,_gzip); - } - -} \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/encoding.properties b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/encoding.properties deleted file mode 100644 index 04fe87e7514..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/encoding.properties +++ /dev/null @@ -1,5 +0,0 @@ -text/html=utf-8 -text/plain=iso-8859-1 -text/xml=utf-8 -text/json=utf-8 -application/xhtml+xml=utf-8 \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/mime.properties b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/mime.properties deleted file mode 100644 index 0112b88a256..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/mime.properties +++ /dev/null @@ -1,189 +0,0 @@ -ai=application/postscript -aif=audio/x-aiff -aifc=audio/x-aiff -aiff=audio/x-aiff -apk=application/vnd.android.package-archive -asc=text/plain -asf=video/x.ms.asf -asx=video/x.ms.asx -au=audio/basic -avi=video/x-msvideo -bcpio=application/x-bcpio -bin=application/octet-stream -bmp=image/bmp -cab=application/x-cabinet -cdf=application/x-netcdf -chm=application/vnd.ms-htmlhelp -class=application/java-vm -cpio=application/x-cpio -cpt=application/mac-compactpro -crt=application/x-x509-ca-cert -csh=application/x-csh -css=text/css -csv=text/csv -dcr=application/x-director -dir=application/x-director -dll=application/x-msdownload -dms=application/octet-stream -doc=application/msword -dtd=application/xml-dtd -dvi=application/x-dvi -dxr=application/x-director -eps=application/postscript -etx=text/x-setext -exe=application/octet-stream -ez=application/andrew-inset -gif=image/gif -gtar=application/x-gtar -gz=application/gzip -gzip=application/gzip -hdf=application/x-hdf -hqx=application/mac-binhex40 -htc=text/x-component -htm=text/html -html=text/html -ice=x-conference/x-cooltalk -ico=image/x-icon -ief=image/ief -iges=model/iges -igs=model/iges -jad=text/vnd.sun.j2me.app-descriptor -jar=application/java-archive -java=text/plain -jnlp=application/x-java-jnlp-file -jpe=image/jpeg -jp2=image/jpeg2000 -jpeg=image/jpeg -jpg=image/jpeg -js=application/javascript -json=application/json -jsp=text/html -kar=audio/midi -latex=application/x-latex -lha=application/octet-stream -lzh=application/octet-stream -man=application/x-troff-man -mathml=application/mathml+xml -me=application/x-troff-me -mesh=model/mesh -mid=audio/midi -midi=audio/midi -mif=application/vnd.mif -mol=chemical/x-mdl-molfile -mov=video/quicktime -movie=video/x-sgi-movie -mp2=audio/mpeg -mp3=audio/mpeg -mpe=video/mpeg -mpeg=video/mpeg -mpg=video/mpeg -mpga=audio/mpeg -ms=application/x-troff-ms -msh=model/mesh -msi=application/octet-stream -nc=application/x-netcdf -oda=application/oda -odb=application/vnd.oasis.opendocument.database -odc=application/vnd.oasis.opendocument.chart -odf=application/vnd.oasis.opendocument.formula -odg=application/vnd.oasis.opendocument.graphics -odi=application/vnd.oasis.opendocument.image -odm=application/vnd.oasis.opendocument.text-master -odp=application/vnd.oasis.opendocument.presentation -ods=application/vnd.oasis.opendocument.spreadsheet -odt=application/vnd.oasis.opendocument.text -ogg=application/ogg -otc=application/vnd.oasis.opendocument.chart-template -otf=application/vnd.oasis.opendocument.formula-template -otg=application/vnd.oasis.opendocument.graphics-template -oth=application/vnd.oasis.opendocument.text-web -oti=application/vnd.oasis.opendocument.image-template -otp=application/vnd.oasis.opendocument.presentation-template -ots=application/vnd.oasis.opendocument.spreadsheet-template -ott=application/vnd.oasis.opendocument.text-template -pbm=image/x-portable-bitmap -pdb=chemical/x-pdb -pdf=application/pdf -pgm=image/x-portable-graymap -pgn=application/x-chess-pgn -png=image/png -pnm=image/x-portable-anymap -ppm=image/x-portable-pixmap -pps=application/vnd.ms-powerpoint -ppt=application/vnd.ms-powerpoint -ps=application/postscript -qml=text/x-qml -qt=video/quicktime -ra=audio/x-pn-realaudio -rar=application/x-rar-compressed -ram=audio/x-pn-realaudio -ras=image/x-cmu-raster -rdf=application/rdf+xml -rgb=image/x-rgb -rm=audio/x-pn-realaudio -roff=application/x-troff -rpm=application/x-rpm -rtf=application/rtf -rtx=text/richtext -rv=video/vnd.rn-realvideo -ser=application/java-serialized-object -sgm=text/sgml -sgml=text/sgml -sh=application/x-sh -shar=application/x-shar -silo=model/mesh -sit=application/x-stuffit -skd=application/x-koan -skm=application/x-koan -skp=application/x-koan -skt=application/x-koan -smi=application/smil -smil=application/smil -snd=audio/basic -spl=application/x-futuresplash -src=application/x-wais-source -sv4cpio=application/x-sv4cpio -sv4crc=application/x-sv4crc -svg=image/svg+xml -svgz=image/svg+xml -swf=application/x-shockwave-flash -t=application/x-troff -tar=application/x-tar -tar.gz=application/x-gtar -tcl=application/x-tcl -tex=application/x-tex -texi=application/x-texinfo -texinfo=application/x-texinfo -tgz=application/x-gtar -tif=image/tiff -tiff=image/tiff -tr=application/x-troff -tsv=text/tab-separated-values -txt=text/plain -ustar=application/x-ustar -vcd=application/x-cdlink -vrml=model/vrml -vxml=application/voicexml+xml -wav=audio/x-wav -wbmp=image/vnd.wap.wbmp -wml=text/vnd.wap.wml -wmlc=application/vnd.wap.wmlc -wmls=text/vnd.wap.wmlscript -wmlsc=application/vnd.wap.wmlscriptc -wrl=model/vrml -wtls-ca-certificate=application/vnd.wap.wtls-ca-certificate -xbm=image/x-xbitmap -xcf=image/xcf -xht=application/xhtml+xml -xhtml=application/xhtml+xml -xls=application/vnd.ms-excel -xml=application/xml -xpm=image/x-xpixmap -xsd=application/xml -xsl=application/xml -xslt=application/xslt+xml -xul=application/vnd.mozilla.xul+xml -xwd=image/x-xwindowdump -xyz=chemical/x-xyz -z=application/compress -zip=application/zip diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/package-info.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/package-info.java deleted file mode 100644 index aeca4a3f2a6..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -/** - * Jetty Http : Tools for Http processing - */ -package org.eclipse.jetty.http; - diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/MappedResource.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/MappedResource.java deleted file mode 100644 index 155dce8b8b5..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/MappedResource.java +++ /dev/null @@ -1,101 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; - -@ManagedObject("Mapped Resource") -public class MappedResource implements Comparable> -{ - private final PathSpec pathSpec; - private final E resource; - - public MappedResource(PathSpec pathSpec, E resource) - { - this.pathSpec = pathSpec; - this.resource = resource; - } - - /** - * Comparison is based solely on the pathSpec - */ - @Override - public int compareTo(MappedResource other) - { - return this.pathSpec.compareTo(other.pathSpec); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - MappedResource other = (MappedResource)obj; - if (pathSpec == null) - { - if (other.pathSpec != null) - { - return false; - } - } - else if (!pathSpec.equals(other.pathSpec)) - { - return false; - } - return true; - } - - @ManagedAttribute(value = "path spec", readonly = true) - public PathSpec getPathSpec() - { - return pathSpec; - } - - @ManagedAttribute(value = "resource", readonly = true) - public E getResource() - { - return resource; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((pathSpec == null) ? 0 : pathSpec.hashCode()); - return result; - } - - @Override - public String toString() - { - return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource); - } -} \ No newline at end of file diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathMappings.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathMappings.java deleted file mode 100644 index d1c36cfbd69..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathMappings.java +++ /dev/null @@ -1,159 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * Path Mappings of PathSpec to Resource. - *

- * Sorted into search order upon entry into the Set - * - * @param the type of mapping endpoint - */ -@ManagedObject("Path Mappings") -public class PathMappings implements Iterable>, Dumpable -{ - private static final Logger LOG = Log.getLogger(PathMappings.class); - private List> mappings = new ArrayList>(); - private MappedResource defaultResource = null; - private MappedResource rootResource = null; - - @Override - public String dump() - { - return ContainerLifeCycle.dump(this); - } - - @Override - public void dump(Appendable out, String indent) throws IOException - { - ContainerLifeCycle.dump(out,indent,mappings); - } - - @ManagedAttribute(value = "mappings", readonly = true) - public List> getMappings() - { - return mappings; - } - - public void reset() - { - mappings.clear(); - } - - /** - * Return a list of MappedResource matches for the specified path. - * - * @param path the path to return matches on - * @return the list of mapped resource the path matches on - */ - public List> getMatches(String path) - { - boolean matchRoot = "/".equals(path); - - List> ret = new ArrayList<>(); - int len = mappings.size(); - for (int i = 0; i < len; i++) - { - MappedResource mr = mappings.get(i); - - switch (mr.getPathSpec().group) - { - case ROOT: - if (matchRoot) - ret.add(mr); - break; - case DEFAULT: - if (matchRoot || mr.getPathSpec().matches(path)) - ret.add(mr); - break; - default: - if (mr.getPathSpec().matches(path)) - ret.add(mr); - break; - } - } - return ret; - } - - public MappedResource getMatch(String path) - { - if (path.equals("/") && rootResource != null) - { - return rootResource; - } - - int len = mappings.size(); - for (int i = 0; i < len; i++) - { - MappedResource mr = mappings.get(i); - if (mr.getPathSpec().matches(path)) - { - return mr; - } - } - return defaultResource; - } - - @Override - public Iterator> iterator() - { - return mappings.iterator(); - } - - @SuppressWarnings("incomplete-switch") - public void put(PathSpec pathSpec, E resource) - { - MappedResource entry = new MappedResource<>(pathSpec,resource); - switch (pathSpec.group) - { - case DEFAULT: - defaultResource = entry; - break; - case ROOT: - rootResource = entry; - break; - } - - // TODO: add warning when replacing an existing pathspec? - - mappings.add(entry); - if (LOG.isDebugEnabled()) - LOG.debug("Added {} to {}",entry,this); - Collections.sort(mappings); - } - - @Override - public String toString() - { - return String.format("%s[size=%d]",this.getClass().getSimpleName(),mappings.size()); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpec.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpec.java deleted file mode 100644 index a2b8ea56cf7..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpec.java +++ /dev/null @@ -1,167 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -/** - * The base PathSpec, what all other path specs are based on - */ -public abstract class PathSpec implements Comparable -{ - protected String pathSpec; - protected PathSpecGroup group; - protected int pathDepth; - protected int specLength; - - @Override - public int compareTo(PathSpec other) - { - // Grouping (increasing) - int diff = this.group.ordinal() - other.group.ordinal(); - if (diff != 0) - { - return diff; - } - - // Spec Length (decreasing) - diff = other.specLength - this.specLength; - if (diff != 0) - { - return diff; - } - - // Path Spec Name (alphabetical) - return this.pathSpec.compareTo(other.pathSpec); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - PathSpec other = (PathSpec)obj; - if (pathSpec == null) - { - if (other.pathSpec != null) - { - return false; - } - } - else if (!pathSpec.equals(other.pathSpec)) - { - return false; - } - return true; - } - - public PathSpecGroup getGroup() - { - return group; - } - - /** - * Get the number of path elements that this path spec declares. - *

- * This is used to determine longest match logic. - * - * @return the depth of the path segments that this spec declares - */ - public int getPathDepth() - { - return pathDepth; - } - - /** - * Return the portion of the path that is after the path spec. - * - * @param path - * the path to match against - * @return the path info portion of the string - */ - public abstract String getPathInfo(String path); - - /** - * Return the portion of the path that matches a path spec. - * - * @param path - * the path to match against - * @return the match, or null if no match at all - */ - public abstract String getPathMatch(String path); - - /** - * The as-provided path spec. - * - * @return the as-provided path spec - */ - public String getDeclaration() - { - return pathSpec; - } - - /** - * Get the relative path. - * - * @param base - * the base the path is relative to - * @param path - * the additional path - * @return the base plus path with pathSpec portion removed - */ - public abstract String getRelativePath(String base, String path); - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode()); - return result; - } - - /** - * Test to see if the provided path matches this path spec - * - * @param path - * the path to test - * @return true if the path matches this path spec, false otherwise - */ - public abstract boolean matches(String path); - - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append(this.getClass().getSimpleName()).append("[\""); - str.append(pathSpec); - str.append("\",pathDepth=").append(pathDepth); - str.append(",group=").append(group); - str.append("]"); - return str.toString(); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecGroup.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecGroup.java deleted file mode 100644 index f9d96ced225..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecGroup.java +++ /dev/null @@ -1,101 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -/** - * Types of path spec groups. - *

- * This is used to facilitate proper pathspec search order. - *

- * Search Order: - *

    - *
  1. {@link PathSpecGroup#ordinal()} [increasing]
  2. - *
  3. {@link PathSpec#specLength} [decreasing]
  4. - *
  5. {@link PathSpec#pathSpec} [natural sort order]
  6. - *
- */ -public enum PathSpecGroup -{ - // NOTE: Order of enums determines order of Groups. - - /** - * For exactly defined path specs, no glob. - */ - EXACT, - /** - * For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle. - * - *
-     *   "^/downloads/[^/]*.zip$"  - regex spec
-     *   "/a/{var}/c"              - uri-template spec
-     * 
- * - * Note: there is no known servlet spec variant of this kind of path spec - */ - MIDDLE_GLOB, - /** - * For path specs that have a hardcoded prefix and a trailing wildcard glob. - *

- * - *

-     *   "/downloads/*"          - servlet spec
-     *   "/api/*"                - servlet spec
-     *   "^/rest/.*$"            - regex spec
-     *   "/bookings/{guest-id}"  - uri-template spec
-     *   "/rewards/{vip-level}"  - uri-template spec
-     * 
- */ - PREFIX_GLOB, - /** - * For path specs that have a wildcard glob with a hardcoded suffix - * - *
-     *   "*.do"        - servlet spec
-     *   "*.css"       - servlet spec
-     *   "^.*\.zip$"   - regex spec
-     * 
- * - * Note: there is no known uri-template spec variant of this kind of path spec - */ - SUFFIX_GLOB, - /** - * The root spec for accessing the Root behavior. - * - *
-     *   ""           - servlet spec       (Root Servlet)
-     *   null         - servlet spec       (Root Servlet)
-     * 
- * - * Note: there is no known uri-template spec variant of this kind of path spec - */ - ROOT, - /** - * The default spec for accessing the Default path behavior. - * - *
-     *   "/"           - servlet spec      (Default Servlet)
-     *   "/"           - uri-template spec (Root Context)
-     *   "^/$"         - regex spec        (Root Context)
-     * 
- * - * Per Servlet Spec, pathInfo is always null for these specs. - * If nothing above matches, then default will match. - */ - DEFAULT, -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecSet.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecSet.java deleted file mode 100644 index c1a32354724..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/PathSpecSet.java +++ /dev/null @@ -1,222 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.function.Predicate; - -/** - * A Set of PathSpec strings. - *

- * Used by {@link org.eclipse.jetty.util.IncludeExclude} logic - */ -public class PathSpecSet implements Set, Predicate -{ - private final Set specs = new TreeSet<>(); - - @Override - public boolean test(String s) - { - for (PathSpec spec : specs) - { - if (spec.matches(s)) - { - return true; - } - } - return false; - } - - @Override - public boolean isEmpty() - { - return specs.isEmpty(); - } - - @Override - public Iterator iterator() - { - return new Iterator() - { - private Iterator iter = specs.iterator(); - - @Override - public boolean hasNext() - { - return iter.hasNext(); - } - - @Override - public String next() - { - PathSpec spec = iter.next(); - if (spec == null) - { - return null; - } - return spec.getDeclaration(); - } - - @Override - public void remove() - { - throw new UnsupportedOperationException("Remove not supported by this Iterator"); - } - }; - } - - @Override - public int size() - { - return specs.size(); - } - - @Override - public boolean contains(Object o) - { - if (o instanceof PathSpec) - { - return specs.contains(o); - } - if (o instanceof String) - { - return specs.contains(toPathSpec((String)o)); - } - return false; - } - - private PathSpec asPathSpec(Object o) - { - if (o == null) - { - return null; - } - if (o instanceof PathSpec) - { - return (PathSpec)o; - } - if (o instanceof String) - { - return toPathSpec((String)o); - } - return toPathSpec(o.toString()); - } - - private PathSpec toPathSpec(String rawSpec) - { - if ((rawSpec == null) || (rawSpec.length() < 1)) - { - throw new RuntimeException("Path Spec String must start with '^', '/', or '*.': got [" + rawSpec + "]"); - } - if (rawSpec.charAt(0) == '^') - { - return new RegexPathSpec(rawSpec); - } - else - { - return new ServletPathSpec(rawSpec); - } - } - - @Override - public Object[] toArray() - { - return toArray(new String[specs.size()]); - } - - @Override - public T[] toArray(T[] a) - { - int i = 0; - for (PathSpec spec : specs) - { - a[i++] = (T)spec.getDeclaration(); - } - return a; - } - - @Override - public boolean add(String e) - { - return specs.add(toPathSpec(e)); - } - - @Override - public boolean remove(Object o) - { - return specs.remove(asPathSpec(o)); - } - - @Override - public boolean containsAll(Collection coll) - { - for (Object o : coll) - { - if (!specs.contains(asPathSpec(o))) - return false; - } - return true; - } - - @Override - public boolean addAll(Collection coll) - { - boolean ret = false; - - for (String s : coll) - { - ret |= add(s); - } - - return ret; - } - - @Override - public boolean retainAll(Collection coll) - { - List collSpecs = new ArrayList<>(); - for (Object o : coll) - { - collSpecs.add(asPathSpec(o)); - } - return specs.retainAll(collSpecs); - } - - @Override - public boolean removeAll(Collection coll) - { - List collSpecs = new ArrayList<>(); - for (Object o : coll) - { - collSpecs.add(asPathSpec(o)); - } - return specs.removeAll(collSpecs); - } - - @Override - public void clear() - { - specs.clear(); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/RegexPathSpec.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/RegexPathSpec.java deleted file mode 100644 index 0d83f3b0003..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/RegexPathSpec.java +++ /dev/null @@ -1,176 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class RegexPathSpec extends PathSpec -{ - protected Pattern pattern; - - protected RegexPathSpec() - { - super(); - } - - public RegexPathSpec(String regex) - { - super.pathSpec = regex; - boolean inGrouping = false; - this.pathDepth = 0; - this.specLength = pathSpec.length(); - // build up a simple signature we can use to identify the grouping - StringBuilder signature = new StringBuilder(); - for (char c : pathSpec.toCharArray()) - { - switch (c) - { - case '[': - inGrouping = true; - break; - case ']': - inGrouping = false; - signature.append('g'); // glob - break; - case '*': - signature.append('g'); // glob - break; - case '/': - if (!inGrouping) - { - this.pathDepth++; - } - break; - default: - if (!inGrouping) - { - if (Character.isLetterOrDigit(c)) - { - signature.append('l'); // literal (exact) - } - } - break; - } - } - this.pattern = Pattern.compile(pathSpec); - - // Figure out the grouping based on the signature - String sig = signature.toString(); - - if (Pattern.matches("^l*$",sig)) - { - this.group = PathSpecGroup.EXACT; - } - else if (Pattern.matches("^l*g+",sig)) - { - this.group = PathSpecGroup.PREFIX_GLOB; - } - else if (Pattern.matches("^g+l+$",sig)) - { - this.group = PathSpecGroup.SUFFIX_GLOB; - } - else - { - this.group = PathSpecGroup.MIDDLE_GLOB; - } - } - - public Matcher getMatcher(String path) - { - return this.pattern.matcher(path); - } - - @Override - public String getPathInfo(String path) - { - // Path Info only valid for PREFIX_GLOB types - if (group == PathSpecGroup.PREFIX_GLOB) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - if (matcher.groupCount() >= 1) - { - String pathInfo = matcher.group(1); - if ("".equals(pathInfo)) - { - return "/"; - } - else - { - return pathInfo; - } - } - } - } - return null; - } - - @Override - public String getPathMatch(String path) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - if (matcher.groupCount() >= 1) - { - int idx = matcher.start(1); - if (idx > 0) - { - if (path.charAt(idx - 1) == '/') - { - idx--; - } - return path.substring(0,idx); - } - } - return path; - } - return null; - } - - public Pattern getPattern() - { - return this.pattern; - } - - @Override - public String getRelativePath(String base, String path) - { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean matches(final String path) - { - int idx = path.indexOf('?'); - if (idx >= 0) - { - // match only non-query part - return getMatcher(path.substring(0,idx)).matches(); - } - else - { - // match entire path - return getMatcher(path).matches(); - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/ServletPathSpec.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/ServletPathSpec.java deleted file mode 100644 index 4563305659c..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/ServletPathSpec.java +++ /dev/null @@ -1,261 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import org.eclipse.jetty.util.URIUtil; - -public class ServletPathSpec extends PathSpec -{ - public ServletPathSpec(String servletPathSpec) - { - super(); - assertValidServletPathSpec(servletPathSpec); - - // The Root Path Spec - if ((servletPathSpec == null) || (servletPathSpec.length() == 0)) - { - super.pathSpec = ""; - super.pathDepth = -1; // force this to be at the end of the sort order - this.specLength = 1; - this.group = PathSpecGroup.ROOT; - return; - } - - // The Default Path Spec - if("/".equals(servletPathSpec)) - { - super.pathSpec = "/"; - super.pathDepth = -1; // force this to be at the end of the sort order - this.specLength = 1; - this.group = PathSpecGroup.DEFAULT; - return; - } - - this.specLength = servletPathSpec.length(); - super.pathDepth = 0; - char lastChar = servletPathSpec.charAt(specLength - 1); - // prefix based - if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*')) - { - this.group = PathSpecGroup.PREFIX_GLOB; - } - // suffix based - else if (servletPathSpec.charAt(0) == '*') - { - this.group = PathSpecGroup.SUFFIX_GLOB; - } - else - { - this.group = PathSpecGroup.EXACT; - } - - for (int i = 0; i < specLength; i++) - { - int cp = servletPathSpec.codePointAt(i); - if (cp < 128) - { - char c = (char)cp; - switch (c) - { - case '/': - super.pathDepth++; - break; - } - } - } - - super.pathSpec = servletPathSpec; - } - - private void assertValidServletPathSpec(String servletPathSpec) - { - if ((servletPathSpec == null) || servletPathSpec.equals("")) - { - return; // empty path spec - } - - int len = servletPathSpec.length(); - // path spec must either start with '/' or '*.' - if (servletPathSpec.charAt(0) == '/') - { - // Prefix Based - if (len == 1) - { - return; // simple '/' path spec - } - int idx = servletPathSpec.indexOf('*'); - if (idx < 0) - { - return; // no hit on glob '*' - } - // only allowed to have '*' at the end of the path spec - if (idx != (len - 1)) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\""); - } - } - else if (servletPathSpec.startsWith("*.")) - { - // Suffix Based - int idx = servletPathSpec.indexOf('/'); - // cannot have path separator - if (idx >= 0) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \""+ servletPathSpec +"\""); - } - - idx = servletPathSpec.indexOf('*',2); - // only allowed to have 1 glob '*', at the start of the path spec - if (idx >= 1) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \""+ servletPathSpec +"\""); - } - } - else - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \""+ servletPathSpec +"\""); - } - } - - @Override - public String getPathInfo(String path) - { - // Path Info only valid for PREFIX_GLOB types - if (group == PathSpecGroup.PREFIX_GLOB) - { - if (path.length() == (specLength - 2)) - { - return null; - } - return path.substring(specLength - 2); - } - - return null; - } - - @Override - public String getPathMatch(String path) - { - switch (group) - { - case EXACT: - if (pathSpec.equals(path)) - { - return path; - } - else - { - return null; - } - case PREFIX_GLOB: - if (isWildcardMatch(path)) - { - return path.substring(0,specLength - 2); - } - else - { - return null; - } - case SUFFIX_GLOB: - if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1)) - { - return path; - } - else - { - return null; - } - case DEFAULT: - return path; - default: - return null; - } - } - - @Override - public String getRelativePath(String base, String path) - { - String info = getPathInfo(path); - if (info == null) - { - info = path; - } - - if (info.startsWith("./")) - { - info = info.substring(2); - } - if (base.endsWith(URIUtil.SLASH)) - { - if (info.startsWith(URIUtil.SLASH)) - { - path = base + info.substring(1); - } - else - { - path = base + info; - } - } - else if (info.startsWith(URIUtil.SLASH)) - { - path = base + info; - } - else - { - path = base + URIUtil.SLASH + info; - } - return path; - } - - private boolean isWildcardMatch(String path) - { - // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar" - int cpl = specLength - 2; - if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl))) - { - if ((path.length() == cpl) || ('/' == path.charAt(cpl))) - { - return true; - } - } - return false; - } - - @Override - public boolean matches(String path) - { - switch (group) - { - case EXACT: - return pathSpec.equals(path); - case PREFIX_GLOB: - return isWildcardMatch(path); - case SUFFIX_GLOB: - return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1); - case ROOT: - // Only "/" matches - return ("/".equals(path)); - case DEFAULT: - // If we reached this point, then everything matches - return true; - default: - return false; - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java deleted file mode 100644 index 208820b6e3b..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java +++ /dev/null @@ -1,341 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http.pathmap; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * PathSpec for URI Template based declarations - * - * @see URI Templates (Level 1) - */ -public class UriTemplatePathSpec extends RegexPathSpec -{ - private static final Logger LOG = Log.getLogger(UriTemplatePathSpec.class); - - private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{(.*)\\}"); - /** Reserved Symbols in URI Template variable */ - private static final String VARIABLE_RESERVED = ":/?#[]@" + // gen-delims - "!$&'()*+,;="; // sub-delims - /** Allowed Symbols in a URI Template variable */ - private static final String VARIABLE_SYMBOLS="-._"; - private static final Set FORBIDDEN_SEGMENTS; - - static - { - FORBIDDEN_SEGMENTS = new HashSet<>(); - FORBIDDEN_SEGMENTS.add("/./"); - FORBIDDEN_SEGMENTS.add("/../"); - FORBIDDEN_SEGMENTS.add("//"); - } - - private String variables[]; - - public UriTemplatePathSpec(String rawSpec) - { - super(); - Objects.requireNonNull(rawSpec,"Path Param Spec cannot be null"); - - if ("".equals(rawSpec) || "/".equals(rawSpec)) - { - super.pathSpec = "/"; - super.pattern = Pattern.compile("^/$"); - super.pathDepth = 1; - this.specLength = 1; - this.variables = new String[0]; - this.group = PathSpecGroup.EXACT; - return; - } - - if (rawSpec.charAt(0) != '/') - { - // path specs must start with '/' - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: path spec \""); - err.append(rawSpec); - err.append("\" must start with '/'"); - throw new IllegalArgumentException(err.toString()); - } - - for (String forbidden : FORBIDDEN_SEGMENTS) - { - if (rawSpec.contains(forbidden)) - { - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: segment "); - err.append(forbidden); - err.append(" is forbidden in path spec: "); - err.append(rawSpec); - throw new IllegalArgumentException(err.toString()); - } - } - - this.pathSpec = rawSpec; - - StringBuilder regex = new StringBuilder(); - regex.append('^'); - - List varNames = new ArrayList<>(); - // split up into path segments (ignoring the first slash that will always be empty) - String segments[] = rawSpec.substring(1).split("/"); - char segmentSignature[] = new char[segments.length]; - this.pathDepth = segments.length; - for (int i = 0; i < segments.length; i++) - { - String segment = segments[i]; - Matcher mat = VARIABLE_PATTERN.matcher(segment); - - if (mat.matches()) - { - // entire path segment is a variable. - String variable = mat.group(1); - if (varNames.contains(variable)) - { - // duplicate variable names - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: variable "); - err.append(variable); - err.append(" is duplicated in path spec: "); - err.append(rawSpec); - throw new IllegalArgumentException(err.toString()); - } - - assertIsValidVariableLiteral(variable); - - segmentSignature[i] = 'v'; // variable - // valid variable name - varNames.add(variable); - // build regex - regex.append("/([^/]+)"); - } - else if (mat.find(0)) - { - // variable exists as partial segment - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: variable "); - err.append(mat.group()); - err.append(" must exist as entire path segment: "); - err.append(rawSpec); - throw new IllegalArgumentException(err.toString()); - } - else if ((segment.indexOf('{') >= 0) || (segment.indexOf('}') >= 0)) - { - // variable is split with a path separator - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: invalid path segment /"); - err.append(segment); - err.append("/ variable declaration incomplete: "); - err.append(rawSpec); - throw new IllegalArgumentException(err.toString()); - } - else if (segment.indexOf('*') >= 0) - { - // glob segment - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: path segment /"); - err.append(segment); - err.append("/ contains a wildcard symbol (not supported by this uri-template implementation): "); - err.append(rawSpec); - throw new IllegalArgumentException(err.toString()); - } - else - { - // valid path segment - segmentSignature[i] = 'e'; // exact - // build regex - regex.append('/'); - // escape regex special characters - for (char c : segment.toCharArray()) - { - if ((c == '.') || (c == '[') || (c == ']') || (c == '\\')) - { - regex.append('\\'); - } - regex.append(c); - } - } - } - - // Handle trailing slash (which is not picked up during split) - if(rawSpec.charAt(rawSpec.length()-1) == '/') - { - regex.append('/'); - } - - regex.append('$'); - - this.pattern = Pattern.compile(regex.toString()); - - int varcount = varNames.size(); - this.variables = varNames.toArray(new String[varcount]); - - // Convert signature to group - String sig = String.valueOf(segmentSignature); - - if (Pattern.matches("^e*$",sig)) - { - this.group = PathSpecGroup.EXACT; - } - else if (Pattern.matches("^e*v+",sig)) - { - this.group = PathSpecGroup.PREFIX_GLOB; - } - else if (Pattern.matches("^v+e+",sig)) - { - this.group = PathSpecGroup.SUFFIX_GLOB; - } - else - { - this.group = PathSpecGroup.MIDDLE_GLOB; - } - } - - /** - * Validate variable literal name, per RFC6570, Section 2.1 Literals - * @param variable - * @param pathParamSpec - */ - private void assertIsValidVariableLiteral(String variable) - { - int len = variable.length(); - - int i = 0; - int codepoint; - boolean valid = (len > 0); // must not be zero length - - while (valid && i < len) - { - codepoint = variable.codePointAt(i); - i += Character.charCount(codepoint); - - // basic letters, digits, or symbols - if (isValidBasicLiteralCodepoint(codepoint)) - { - continue; - } - - // The ucschar and iprivate pieces - if (Character.isSupplementaryCodePoint(codepoint)) - { - continue; - } - - // pct-encoded - if (codepoint == '%') - { - if (i + 2 > len) - { - // invalid percent encoding, missing extra 2 chars - valid = false; - continue; - } - codepoint = TypeUtil.convertHexDigit(variable.codePointAt(i++)) << 4; - codepoint |= TypeUtil.convertHexDigit(variable.codePointAt(i++)); - - // validate basic literal - if (isValidBasicLiteralCodepoint(codepoint)) - { - continue; - } - } - - valid = false; - } - - if (!valid) - { - // invalid variable name - StringBuilder err = new StringBuilder(); - err.append("Syntax Error: variable {"); - err.append(variable); - err.append("} an invalid variable name: "); - err.append(pathSpec); - throw new IllegalArgumentException(err.toString()); - } - } - - private boolean isValidBasicLiteralCodepoint(int codepoint) - { - // basic letters or digits - if((codepoint >= 'a' && codepoint <= 'z') || - (codepoint >= 'A' && codepoint <= 'Z') || - (codepoint >= '0' && codepoint <= '9')) - { - return true; - } - - // basic allowed symbols - if(VARIABLE_SYMBOLS.indexOf(codepoint) >= 0) - { - return true; // valid simple value - } - - // basic reserved symbols - if(VARIABLE_RESERVED.indexOf(codepoint) >= 0) - { - LOG.warn("Detected URI Template reserved symbol [{}] in path spec \"{}\"",(char)codepoint,pathSpec); - return false; // valid simple value - } - - return false; - } - - public Map getPathParams(String path) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - if (group == PathSpecGroup.EXACT) - { - return Collections.emptyMap(); - } - Map ret = new HashMap<>(); - int groupCount = matcher.groupCount(); - for (int i = 1; i <= groupCount; i++) - { - ret.put(this.variables[i - 1],matcher.group(i)); - } - return ret; - } - return null; - } - - public int getVariableCount() - { - return variables.length; - } - - public String[] getVariables() - { - return this.variables; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java deleted file mode 100644 index 155b3f75201..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ /dev/null @@ -1,43 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http2.hpack; - -import org.eclipse.jetty.http.HostPortHttpField; -import org.eclipse.jetty.http.HttpHeader; - - -/* ------------------------------------------------------------ */ -/** - */ -public class AuthorityHttpField extends HostPortHttpField -{ - public final static String AUTHORITY = HpackContext.STATIC_TABLE[1][0]; - - public AuthorityHttpField(String authority) - { - super(HttpHeader.C_AUTHORITY,AUTHORITY,authority); - } - - @Override - public String toString() - { - return String.format("%s(preparsed h=%s p=%d)",super.toString(),getHost(),getPort()); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackContext.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackContext.java deleted file mode 100644 index 89fbf00e4ad..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackContext.java +++ /dev/null @@ -1,515 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.util.ArrayQueue; -import org.eclipse.jetty.util.ArrayTernaryTrie; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.Trie; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/* ------------------------------------------------------------ */ -/** HPACK - Header Compression for HTTP/2 - *

This class maintains the compression context for a single HTTP/2 - * connection. Specifically it holds the static and dynamic Header Field Tables - * and the associated sizes and limits. - *

- *

It is compliant with draft 11 of the specification

- */ -public class HpackContext -{ - public static final Logger LOG = Log.getLogger(HpackContext.class); - - public static final String[][] STATIC_TABLE = - { - {null,null}, - /* 1 */ {":authority",null}, - /* 2 */ {":method","GET"}, - /* 3 */ {":method","POST"}, - /* 4 */ {":path","/"}, - /* 5 */ {":path","/index.html"}, - /* 6 */ {":scheme","http"}, - /* 7 */ {":scheme","https"}, - /* 8 */ {":status","200"}, - /* 9 */ {":status","204"}, - /* 10 */ {":status","206"}, - /* 11 */ {":status","304"}, - /* 12 */ {":status","400"}, - /* 13 */ {":status","404"}, - /* 14 */ {":status","500"}, - /* 15 */ {"accept-charset",null}, - /* 16 */ {"accept-encoding","gzip, deflate"}, - /* 17 */ {"accept-language",null}, - /* 18 */ {"accept-ranges",null}, - /* 19 */ {"accept",null}, - /* 20 */ {"access-control-allow-origin",null}, - /* 21 */ {"age",null}, - /* 22 */ {"allow",null}, - /* 23 */ {"authorization",null}, - /* 24 */ {"cache-control",null}, - /* 25 */ {"content-disposition",null}, - /* 26 */ {"content-encoding",null}, - /* 27 */ {"content-language",null}, - /* 28 */ {"content-length",null}, - /* 29 */ {"content-location",null}, - /* 30 */ {"content-range",null}, - /* 31 */ {"content-type",null}, - /* 32 */ {"cookie",null}, - /* 33 */ {"date",null}, - /* 34 */ {"etag",null}, - /* 35 */ {"expect",null}, - /* 36 */ {"expires",null}, - /* 37 */ {"from",null}, - /* 38 */ {"host",null}, - /* 39 */ {"if-match",null}, - /* 40 */ {"if-modified-since",null}, - /* 41 */ {"if-none-match",null}, - /* 42 */ {"if-range",null}, - /* 43 */ {"if-unmodified-since",null}, - /* 44 */ {"last-modified",null}, - /* 45 */ {"link",null}, - /* 46 */ {"location",null}, - /* 47 */ {"max-forwards",null}, - /* 48 */ {"proxy-authenticate",null}, - /* 49 */ {"proxy-authorization",null}, - /* 50 */ {"range",null}, - /* 51 */ {"referer",null}, - /* 52 */ {"refresh",null}, - /* 53 */ {"retry-after",null}, - /* 54 */ {"server",null}, - /* 55 */ {"set-cookie",null}, - /* 56 */ {"strict-transport-security",null}, - /* 57 */ {"transfer-encoding",null}, - /* 58 */ {"user-agent",null}, - /* 59 */ {"vary",null}, - /* 60 */ {"via",null}, - /* 61 */ {"www-authenticate",null}, - }; - - private static final Map __staticFieldMap = new HashMap<>(); - private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true,512); - private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.UNKNOWN.ordinal()]; - private static final StaticEntry[] __staticTable=new StaticEntry[STATIC_TABLE.length]; - static - { - Set added = new HashSet<>(); - for (int i=1;i _fieldMap = new HashMap<>(); - private final Map _nameMap = new HashMap<>(); - - HpackContext(int maxDynamicTableSize) - { - _maxDynamicTableSizeInBytes=maxDynamicTableSize; - int guesstimateEntries = 10+maxDynamicTableSize/(32+10+10); - _dynamicTable=new DynamicTable(guesstimateEntries,guesstimateEntries+10); - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] created max=%d",hashCode(),maxDynamicTableSize)); - } - - public void resize(int newMaxDynamicTableSize) - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d",hashCode(),_maxDynamicTableSizeInBytes,newMaxDynamicTableSize)); - _maxDynamicTableSizeInBytes=newMaxDynamicTableSize; - int guesstimateEntries = 10+newMaxDynamicTableSize/(32+10+10); - evict(); - _dynamicTable.resizeUnsafe(guesstimateEntries); - } - - public Entry get(HttpField field) - { - Entry entry = _fieldMap.get(field); - if (entry==null) - entry=__staticFieldMap.get(field); - return entry; - } - - public Entry get(String name) - { - Entry entry = __staticNameMap.get(name); - if (entry!=null) - return entry; - return _nameMap.get(StringUtil.asciiToLowerCase(name)); - } - - public Entry get(int index) - { - if (index<__staticTable.length) - return __staticTable[index]; - - int d=_dynamicTable.size()-index+__staticTable.length-1; - - if (d>=0) - return _dynamicTable.getUnsafe(d); - return null; - } - - public Entry get(HttpHeader header) - { - Entry e = __staticTableByHeader[header.ordinal()]; - if (e==null) - return get(header.asString()); - return e; - } - - public static Entry getStatic(HttpHeader header) - { - return __staticTableByHeader[header.ordinal()]; - } - - public Entry add(HttpField field) - { - int slot=_dynamicTable.getNextSlotUnsafe(); - Entry entry=new Entry(slot,field); - int size = entry.getSize(); - if (size>_maxDynamicTableSizeInBytes) - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] !added size %d>%d",hashCode(),size,_maxDynamicTableSizeInBytes)); - return null; - } - _dynamicTableSizeInBytes+=size; - _dynamicTable.addUnsafe(entry); - _fieldMap.put(field,entry); - _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); - - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] added %s",hashCode(),entry)); - evict(); - return entry; - } - - /** - * @return Current dynamic table size in entries - */ - public int size() - { - return _dynamicTable.size(); - } - - /** - * @return Current Dynamic table size in Octets - */ - public int getDynamicTableSize() - { - return _dynamicTableSizeInBytes; - } - - /** - * @return Max Dynamic table size in Octets - */ - public int getMaxDynamicTableSize() - { - return _maxDynamicTableSizeInBytes; - } - - public int index(Entry entry) - { - if (entry._slot<0) - return 0; - if (entry.isStatic()) - return entry._slot; - - return _dynamicTable.index(entry)+__staticTable.length-1; - } - - public static int staticIndex(HttpHeader header) - { - if (header==null) - return 0; - Entry entry=__staticNameMap.get(header.asString()); - if (entry==null) - return 0; - return entry.getSlot(); - } - - private void evict() - { - while (_dynamicTableSizeInBytes>_maxDynamicTableSizeInBytes) - { - Entry entry = _dynamicTable.pollUnsafe(); - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] evict %s",hashCode(),entry)); - _dynamicTableSizeInBytes-=entry.getSize(); - entry._slot=-1; - _fieldMap.remove(entry.getHttpField()); - String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName()); - if (entry==_nameMap.get(lc)) - _nameMap.remove(lc); - } - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d",hashCode(),_dynamicTable.size(),_dynamicTableSizeInBytes,_maxDynamicTableSizeInBytes)); - } - - @Override - public String toString() - { - return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}",hashCode(),_dynamicTable.size(),_dynamicTableSizeInBytes,_maxDynamicTableSizeInBytes); - } - - - - /* ------------------------------------------------------------ */ - /** - */ - private class DynamicTable extends ArrayQueue - { - /* ------------------------------------------------------------ */ - /** - * @param initCapacity - * @param growBy - */ - private DynamicTable(int initCapacity, int growBy) - { - super(initCapacity,growBy); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.ArrayQueue#growUnsafe() - */ - @Override - protected void resizeUnsafe(int newCapacity) - { - // Relay on super.growUnsafe to pack all entries 0 to _nextSlot - super.resizeUnsafe(newCapacity); - for (int s=0;s<_nextSlot;s++) - ((Entry)_elements[s])._slot=s; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.ArrayQueue#enqueue(java.lang.Object) - */ - @Override - public boolean enqueue(Entry e) - { - return super.enqueue(e); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.ArrayQueue#dequeue() - */ - @Override - public Entry dequeue() - { - return super.dequeue(); - } - - /* ------------------------------------------------------------ */ - /** - * @param entry - * @return - */ - private int index(Entry entry) - { - return entry._slot>=_nextE?_size-entry._slot+_nextE:_nextSlot-entry._slot; - } - - } - - - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static class Entry - { - final HttpField _field; - int _slot; - - Entry() - { - _slot=0; - _field=null; - } - - Entry(int index,String name, String value) - { - _slot=index; - _field=new HttpField(name,value); - } - - Entry(int slot, HttpField field) - { - _slot=slot; - _field=field; - } - - public int getSize() - { - return 32+_field.getName().length()+_field.getValue().length(); - } - - public HttpField getHttpField() - { - return _field; - } - - public boolean isStatic() - { - return false; - } - - public byte[] getStaticHuffmanValue() - { - return null; - } - - public int getSlot() - { - return _slot; - } - - public String toString() - { - return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_slot,_field,hashCode()); - } - } - - public static class StaticEntry extends Entry - { - private final byte[] _huffmanValue; - private final byte _encodedField; - - StaticEntry(int index,HttpField field) - { - super(index,field); - String value = field.getValue(); - if (value!=null && value.length()>0) - { - int huffmanLen = Huffman.octetsNeeded(value); - int lenLen = NBitInteger.octectsNeeded(7,huffmanLen); - _huffmanValue = new byte[1+lenLen+huffmanLen]; - ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); - - // Indicate Huffman - buffer.put((byte)0x80); - // Add huffman length - NBitInteger.encode(buffer,7,huffmanLen); - // Encode value - Huffman.encode(buffer,value); - } - else - _huffmanValue=null; - - _encodedField=(byte)(0x80|index); - } - - @Override - public boolean isStatic() - { - return true; - } - - @Override - public byte[] getStaticHuffmanValue() - { - return _huffmanValue; - } - - public byte getEncodedField() - { - return _encodedField; - } - } - - -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackDecoder.java deleted file mode 100644 index 38dc8567f1f..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ /dev/null @@ -1,280 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.http.BadMessageException; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.hpack.HpackContext.Entry; -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * Hpack Decoder - *

This is not thread safe and may only be called by 1 thread at a time.

- */ -public class HpackDecoder -{ - public static final Logger LOG = Log.getLogger(HpackDecoder.class); - public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = - new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); - - private final HpackContext _context; - private final MetaDataBuilder _builder; - private int _localMaxDynamicTableSize; - - /** - * @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table. - * @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters. - */ - public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize) - { - _context=new HpackContext(localMaxDynamicTableSize); - _localMaxDynamicTableSize=localMaxDynamicTableSize; - _builder = new MetaDataBuilder(maxHeaderSize); - } - - public HpackContext getHpackContext() - { - return _context; - } - - public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize) - { - _localMaxDynamicTableSize=localMaxdynamciTableSize; - } - - public MetaData decode(ByteBuffer buffer) - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining())); - - // If the buffer is big, don't even think about decoding it - if (buffer.remaining()>_builder.getMaxSize()) - throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize()); - - - while(buffer.hasRemaining()) - { - if (LOG.isDebugEnabled()) - { - int l=Math.min(buffer.remaining(),16); - // TODO: not guaranteed the buffer has a backing array ! - LOG.debug("decode {}{}", - TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l), - l>4); - String name; - HttpHeader header; - String value; - - boolean indexed; - int name_index; - - switch (f) - { - case 2: // 7.3 - case 3: // 7.3 - // change table size - int size = NBitInteger.decode(buffer,5); - if (LOG.isDebugEnabled()) - LOG.debug("decode resize="+size); - if (size>_localMaxDynamicTableSize) - throw new IllegalArgumentException(); - _context.resize(size); - continue; - - case 0: // 7.2.2 - case 1: // 7.2.3 - indexed=false; - name_index=NBitInteger.decode(buffer,4); - break; - - - case 4: // 7.2.1 - case 5: // 7.2.1 - case 6: // 7.2.1 - case 7: // 7.2.1 - indexed=true; - name_index=NBitInteger.decode(buffer,6); - break; - - default: - throw new IllegalStateException(); - } - - - boolean huffmanName=false; - - // decode the name - if (name_index>0) - { - Entry name_entry=_context.get(name_index); - name=name_entry.getHttpField().getName(); - header=name_entry.getHttpField().getHeader(); - } - else - { - huffmanName = (buffer.get()&0x80)==0x80; - int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanName); - if (huffmanName) - name=Huffman.decode(buffer,length); - else - name=toASCIIString(buffer,length); - for (int i=0;i='A'&&c<='Z') - { - throw new BadMessageException(400,"Uppercase header name"); - } - } - header=HttpHeader.CACHE.get(name); - } - - // decode the value - boolean huffmanValue = (buffer.get()&0x80)==0x80; - int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanValue); - if (huffmanValue) - value=Huffman.decode(buffer,length); - else - value=toASCIIString(buffer,length); - - // Make the new field - HttpField field; - if (header==null) - { - // just make a normal field and bypass header name lookup - field = new HttpField(null,name,value); - } - else - { - // might be worthwhile to create a value HttpField if it is indexed - // and/or of a type that may be looked up multiple times. - switch(header) - { - case C_STATUS: - if (indexed) - field = new HttpField.IntValueHttpField(header,name,value); - else - field = new HttpField(header,name,value); - break; - - case C_AUTHORITY: - field = new AuthorityHttpField(value); - break; - - case CONTENT_LENGTH: - if ("0".equals(value)) - field = CONTENT_LENGTH_0; - else - field = new HttpField.LongValueHttpField(header,name,value); - break; - - default: - field = new HttpField(header,name,value); - break; - } - } - - if (LOG.isDebugEnabled()) - { - LOG.debug("decoded '{}' by {}/{}/{}", - field, - name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"), - huffmanValue ? "HuffVal" : "LitVal", - indexed ? "Idx" : ""); - } - - // emit the field - _builder.emit(field); - - // if indexed - if (indexed) - { - // add to dynamic table - _context.add(field); - } - - } - } - - return _builder.build(); - } - - public static String toASCIIString(ByteBuffer buffer,int length) - { - StringBuilder builder = new StringBuilder(length); - int position=buffer.position(); - int start=buffer.arrayOffset()+ position; - int end=start+length; - buffer.position(position+length); - byte[] array=buffer.array(); - for (int i=start;i __DO_NOT_HUFFMAN = - EnumSet.of( - HttpHeader.AUTHORIZATION, - HttpHeader.CONTENT_MD5, - HttpHeader.PROXY_AUTHENTICATE, - HttpHeader.PROXY_AUTHORIZATION); - - final static EnumSet __DO_NOT_INDEX = - EnumSet.of( - // HttpHeader.C_PATH, // TODO more data needed - // HttpHeader.DATE, // TODO more data needed - HttpHeader.AUTHORIZATION, - HttpHeader.CONTENT_MD5, - HttpHeader.CONTENT_RANGE, - HttpHeader.ETAG, - HttpHeader.IF_MODIFIED_SINCE, - HttpHeader.IF_UNMODIFIED_SINCE, - HttpHeader.IF_NONE_MATCH, - HttpHeader.IF_RANGE, - HttpHeader.IF_MATCH, - HttpHeader.LOCATION, - HttpHeader.RANGE, - HttpHeader.RETRY_AFTER, - // HttpHeader.EXPIRES, - HttpHeader.LAST_MODIFIED, - HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2); - - - final static EnumSet __NEVER_INDEX = - EnumSet.of( - HttpHeader.AUTHORIZATION, - HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2); - - static - { - for (HttpStatus.Code code : HttpStatus.Code.values()) - __status[code.getCode()]=new PreEncodedHttpField(HttpHeader.C_STATUS,Integer.toString(code.getCode())); - } - - private final HpackContext _context; - private final boolean _debug; - private int _remoteMaxDynamicTableSize; - private int _localMaxDynamicTableSize; - - public HpackEncoder() - { - this(4096,4096); - } - - public HpackEncoder(int localMaxDynamicTableSize) - { - this(localMaxDynamicTableSize,4096); - } - - public HpackEncoder(int localMaxDynamicTableSize,int remoteMaxDynamicTableSize) - { - _context=new HpackContext(remoteMaxDynamicTableSize); - _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize; - _localMaxDynamicTableSize=localMaxDynamicTableSize; - _debug=LOG.isDebugEnabled(); - } - - public HpackContext getHpackContext() - { - return _context; - } - - public void setRemoteMaxDynamicTableSize(int remoteMaxDynamicTableSize) - { - _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize; - } - - public void setLocalMaxDynamicTableSize(int localMaxDynamicTableSize) - { - _localMaxDynamicTableSize=localMaxDynamicTableSize; - } - - public void encode(ByteBuffer buffer, MetaData metadata) - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] encoding",_context.hashCode())); - - int pos = buffer.position(); - - // Check the dynamic table sizes! - int maxDynamicTableSize=Math.min(_remoteMaxDynamicTableSize,_localMaxDynamicTableSize); - if (maxDynamicTableSize!=_context.getMaxDynamicTableSize()) - encodeMaxDynamicTableSize(buffer,maxDynamicTableSize); - - // Add Request/response meta fields - if (metadata.isRequest()) - { - MetaData.Request request = (MetaData.Request)metadata; - - // TODO optimise these to avoid HttpField creation - String scheme=request.getURI().getScheme(); - encode(buffer,new HttpField(HttpHeader.C_SCHEME,scheme==null?HttpScheme.HTTP.asString():scheme)); - encode(buffer,new HttpField(HttpHeader.C_METHOD,request.getMethod())); - encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority())); - encode(buffer,new HttpField(HttpHeader.C_PATH,request.getURI().getPathQuery())); - - } - else if (metadata.isResponse()) - { - MetaData.Response response = (MetaData.Response)metadata; - int code=response.getStatus(); - HttpField status = code<__status.length?__status[code]:null; - if (status==null) - status=new HttpField.IntValueHttpField(HttpHeader.C_STATUS,code); - encode(buffer,status); - } - - // Add all the other fields - for (HttpField field : metadata) - encode(buffer,field); - - if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos)); - } - - public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxDynamicTableSize) - { - if (maxDynamicTableSize>_remoteMaxDynamicTableSize) - throw new IllegalArgumentException(); - buffer.put((byte)0x20); - NBitInteger.encode(buffer,5,maxDynamicTableSize); - _context.resize(maxDynamicTableSize); - } - - public void encode(ByteBuffer buffer, HttpField field) - { - final int p=_debug?buffer.position():-1; - - String encoding=null; - - // Is there an entry for the field? - Entry entry = _context.get(field); - if (entry!=null) - { - // Known field entry, so encode it as indexed - if (entry.isStatic()) - { - buffer.put(((StaticEntry)entry).getEncodedField()); - if (_debug) - encoding="IdxFieldS1"; - } - else - { - int index=_context.index(entry); - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); - if (_debug) - encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); - } - } - else - { - // Unknown field entry, so we will have to send literally. - final boolean indexed; - - // But do we know it's name? - HttpHeader header = field.getHeader(); - - // Select encoding strategy - if (header==null) - { - // Select encoding strategy for unknown header names - Entry name = _context.get(field.getName()); - - if (field instanceof PreEncodedHttpField) - { - int i=buffer.position(); - ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2); - byte b=buffer.get(i); - indexed=b<0||b>=0x40; - if (_debug) - encoding=indexed?"PreEncodedIdx":"PreEncoded"; - } - // has the custom header name been seen before? - else if (name==null) - { - // unknown name and value, so let's index this just in case it is - // the first time we have seen a custom name or a custom field. - // unless the name is changing, this is worthwhile - indexed=true; - encodeName(buffer,(byte)0x40,6,field.getName(),null); - encodeValue(buffer,true,field.getValue()); - if (_debug) - encoding="LitHuffNHuffVIdx"; - } - else - { - // known custom name, but unknown value. - // This is probably a custom field with changing value, so don't index. - indexed=false; - encodeName(buffer,(byte)0x00,4,field.getName(),null); - encodeValue(buffer,true,field.getValue()); - if (_debug) - encoding="LitHuffNHuffV!Idx"; - } - } - else - { - // Select encoding strategy for known header names - Entry name = _context.get(header); - - if (field instanceof PreEncodedHttpField) - { - // Preencoded field - int i=buffer.position(); - ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2); - byte b=buffer.get(i); - indexed=b<0||b>=0x40; - if (_debug) - encoding=indexed?"PreEncodedIdx":"PreEncoded"; - } - else if (__DO_NOT_INDEX.contains(header)) - { - // Non indexed field - indexed=false; - boolean never_index=__NEVER_INDEX.contains(header); - boolean huffman=!__DO_NOT_HUFFMAN.contains(header); - encodeName(buffer,never_index?(byte)0x10:(byte)0x00,4,header.asString(),name); - encodeValue(buffer,huffman,field.getValue()); - - if (_debug) - encoding="Lit"+ - ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(4,_context.index(name)))))+ - (huffman?"HuffV":"LitV")+ - (indexed?"Idx":(never_index?"!!Idx":"!Idx")); - } - else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) - { - // Non indexed content length for 2 digits or more - indexed=false; - encodeName(buffer,(byte)0x00,4,header.asString(),name); - encodeValue(buffer,true,field.getValue()); - if (_debug) - encoding="LitIdxNS"+(1+NBitInteger.octectsNeeded(4,_context.index(name)))+"HuffV!Idx"; - } - else - { - // indexed - indexed=true; - boolean huffman=!__DO_NOT_HUFFMAN.contains(header); - encodeName(buffer,(byte)0x40,6,header.asString(),name); - encodeValue(buffer,huffman,field.getValue()); - if (_debug) - encoding=((name==null)?"LitHuffN":("LitIdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(6,_context.index(name)))))+ - (huffman?"HuffVIdx":"LitVIdx"); - } - } - - // If we want the field referenced, then we add it to our - // table and reference set. - if (indexed) - _context.add(field); - } - - if (_debug) - { - int e=buffer.position(); - if (LOG.isDebugEnabled()) - LOG.debug("encode {}:'{}' to '{}'",encoding,field,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); - } - } - - private void encodeName(ByteBuffer buffer, byte mask, int bits, String name, Entry entry) - { - buffer.put(mask); - if (entry==null) - { - // leave name index bits as 0 - // Encode the name always with lowercase huffman - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name)); - Huffman.encodeLC(buffer,name); - } - else - { - NBitInteger.encode(buffer,bits,_context.index(entry)); - } - } - - static void encodeValue(ByteBuffer buffer, boolean huffman, String value) - { - if (huffman) - { - // huffman literal value - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); - Huffman.encode(buffer,value); - } - else - { - // add literal assuming iso_8859_1 - buffer.put((byte)0x00); - NBitInteger.encode(buffer,7,value.length()); - for (int i=0;i127) - throw new IllegalArgumentException(); - buffer.put((byte)c); - } - } - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java deleted file mode 100644 index f73b34728ee..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java +++ /dev/null @@ -1,97 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.http.HttpFieldPreEncoder; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.util.BufferUtil; - - -/* ------------------------------------------------------------ */ -/** - */ -public class HpackFieldPreEncoder implements HttpFieldPreEncoder -{ - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() - */ - @Override - public HttpVersion getHttpVersion() - { - return HttpVersion.HTTP_2; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String) - */ - @Override - public byte[] getEncodedField(HttpHeader header, String name, String value) - { - boolean not_indexed=HpackEncoder.__DO_NOT_INDEX.contains(header); - - ByteBuffer buffer = BufferUtil.allocate(name.length()+value.length()+10); - BufferUtil.clearToFill(buffer); - boolean huffman; - int bits; - - if (not_indexed) - { - // Non indexed field - boolean never_index=HpackEncoder.__NEVER_INDEX.contains(header); - huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header); - buffer.put(never_index?(byte)0x10:(byte)0x00); - bits=4; - } - else if (header==HttpHeader.CONTENT_LENGTH && value.length()>1) - { - // Non indexed content length for 2 digits or more - buffer.put((byte)0x00); - huffman=true; - bits=4; - } - else - { - // indexed - buffer.put((byte)0x40); - huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header); - bits=6; - } - - int name_idx=HpackContext.staticIndex(header); - if (name_idx>0) - NBitInteger.encode(buffer,bits,name_idx); - else - { - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name)); - Huffman.encodeLC(buffer,name); - } - - HpackEncoder.encodeValue(buffer,huffman,value); - - BufferUtil.flipToFlush(buffer,0); - return BufferUtil.toArray(buffer); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/Huffman.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/Huffman.java deleted file mode 100644 index da28684c4ad..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/Huffman.java +++ /dev/null @@ -1,480 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -public class Huffman -{ - - // Appendix C: Huffman Codes - // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C - static final int[][] CODES = - { - /* ( 0) |11111111|11000 */ {0x1ff8,13}, - /* ( 1) |11111111|11111111|1011000 */ {0x7fffd8,23}, - /* ( 2) |11111111|11111111|11111110|0010 */ {0xfffffe2,28}, - /* ( 3) |11111111|11111111|11111110|0011 */ {0xfffffe3,28}, - /* ( 4) |11111111|11111111|11111110|0100 */ {0xfffffe4,28}, - /* ( 5) |11111111|11111111|11111110|0101 */ {0xfffffe5,28}, - /* ( 6) |11111111|11111111|11111110|0110 */ {0xfffffe6,28}, - /* ( 7) |11111111|11111111|11111110|0111 */ {0xfffffe7,28}, - /* ( 8) |11111111|11111111|11111110|1000 */ {0xfffffe8,28}, - /* ( 9) |11111111|11111111|11101010 */ {0xffffea,24}, - /* ( 10) |11111111|11111111|11111111|111100 */ {0x3ffffffc,30}, - /* ( 11) |11111111|11111111|11111110|1001 */ {0xfffffe9,28}, - /* ( 12) |11111111|11111111|11111110|1010 */ {0xfffffea,28}, - /* ( 13) |11111111|11111111|11111111|111101 */ {0x3ffffffd,30}, - /* ( 14) |11111111|11111111|11111110|1011 */ {0xfffffeb,28}, - /* ( 15) |11111111|11111111|11111110|1100 */ {0xfffffec,28}, - /* ( 16) |11111111|11111111|11111110|1101 */ {0xfffffed,28}, - /* ( 17) |11111111|11111111|11111110|1110 */ {0xfffffee,28}, - /* ( 18) |11111111|11111111|11111110|1111 */ {0xfffffef,28}, - /* ( 19) |11111111|11111111|11111111|0000 */ {0xffffff0,28}, - /* ( 20) |11111111|11111111|11111111|0001 */ {0xffffff1,28}, - /* ( 21) |11111111|11111111|11111111|0010 */ {0xffffff2,28}, - /* ( 22) |11111111|11111111|11111111|111110 */ {0x3ffffffe,30}, - /* ( 23) |11111111|11111111|11111111|0011 */ {0xffffff3,28}, - /* ( 24) |11111111|11111111|11111111|0100 */ {0xffffff4,28}, - /* ( 25) |11111111|11111111|11111111|0101 */ {0xffffff5,28}, - /* ( 26) |11111111|11111111|11111111|0110 */ {0xffffff6,28}, - /* ( 27) |11111111|11111111|11111111|0111 */ {0xffffff7,28}, - /* ( 28) |11111111|11111111|11111111|1000 */ {0xffffff8,28}, - /* ( 29) |11111111|11111111|11111111|1001 */ {0xffffff9,28}, - /* ( 30) |11111111|11111111|11111111|1010 */ {0xffffffa,28}, - /* ( 31) |11111111|11111111|11111111|1011 */ {0xffffffb,28}, - /*' ' ( 32) |010100 */ {0x14, 6}, - /*'!' ( 33) |11111110|00 */ {0x3f8,10}, - /*'"' ( 34) |11111110|01 */ {0x3f9,10}, - /*'#' ( 35) |11111111|1010 */ {0xffa,12}, - /*'$' ( 36) |11111111|11001 */ {0x1ff9,13}, - /*'%' ( 37) |010101 */ {0x15, 6}, - /*'&' ( 38) |11111000 */ {0xf8, 8}, - /*''' ( 39) |11111111|010 */ {0x7fa,11}, - /*'(' ( 40) |11111110|10 */ {0x3fa,10}, - /*')' ( 41) |11111110|11 */ {0x3fb,10}, - /*'*' ( 42) |11111001 */ {0xf9, 8}, - /*'+' ( 43) |11111111|011 */ {0x7fb,11}, - /*',' ( 44) |11111010 */ {0xfa, 8}, - /*'-' ( 45) |010110 */ {0x16, 6}, - /*'.' ( 46) |010111 */ {0x17, 6}, - /*'/' ( 47) |011000 */ {0x18, 6}, - /*'0' ( 48) |00000 */ {0x0, 5}, - /*'1' ( 49) |00001 */ {0x1, 5}, - /*'2' ( 50) |00010 */ {0x2, 5}, - /*'3' ( 51) |011001 */ {0x19, 6}, - /*'4' ( 52) |011010 */ {0x1a, 6}, - /*'5' ( 53) |011011 */ {0x1b, 6}, - /*'6' ( 54) |011100 */ {0x1c, 6}, - /*'7' ( 55) |011101 */ {0x1d, 6}, - /*'8' ( 56) |011110 */ {0x1e, 6}, - /*'9' ( 57) |011111 */ {0x1f, 6}, - /*':' ( 58) |1011100 */ {0x5c, 7}, - /*';' ( 59) |11111011 */ {0xfb, 8}, - /*'<' ( 60) |11111111|1111100 */ {0x7ffc,15}, - /*'=' ( 61) |100000 */ {0x20, 6}, - /*'>' ( 62) |11111111|1011 */ {0xffb,12}, - /*'?' ( 63) |11111111|00 */ {0x3fc,10}, - /*'@' ( 64) |11111111|11010 */ {0x1ffa,13}, - /*'A' ( 65) |100001 */ {0x21, 6}, - /*'B' ( 66) |1011101 */ {0x5d, 7}, - /*'C' ( 67) |1011110 */ {0x5e, 7}, - /*'D' ( 68) |1011111 */ {0x5f, 7}, - /*'E' ( 69) |1100000 */ {0x60, 7}, - /*'F' ( 70) |1100001 */ {0x61, 7}, - /*'G' ( 71) |1100010 */ {0x62, 7}, - /*'H' ( 72) |1100011 */ {0x63, 7}, - /*'I' ( 73) |1100100 */ {0x64, 7}, - /*'J' ( 74) |1100101 */ {0x65, 7}, - /*'K' ( 75) |1100110 */ {0x66, 7}, - /*'L' ( 76) |1100111 */ {0x67, 7}, - /*'M' ( 77) |1101000 */ {0x68, 7}, - /*'N' ( 78) |1101001 */ {0x69, 7}, - /*'O' ( 79) |1101010 */ {0x6a, 7}, - /*'P' ( 80) |1101011 */ {0x6b, 7}, - /*'Q' ( 81) |1101100 */ {0x6c, 7}, - /*'R' ( 82) |1101101 */ {0x6d, 7}, - /*'S' ( 83) |1101110 */ {0x6e, 7}, - /*'T' ( 84) |1101111 */ {0x6f, 7}, - /*'U' ( 85) |1110000 */ {0x70, 7}, - /*'V' ( 86) |1110001 */ {0x71, 7}, - /*'W' ( 87) |1110010 */ {0x72, 7}, - /*'X' ( 88) |11111100 */ {0xfc, 8}, - /*'Y' ( 89) |1110011 */ {0x73, 7}, - /*'Z' ( 90) |11111101 */ {0xfd, 8}, - /*'[' ( 91) |11111111|11011 */ {0x1ffb,13}, - /*'\' ( 92) |11111111|11111110|000 */ {0x7fff0,19}, - /*']' ( 93) |11111111|11100 */ {0x1ffc,13}, - /*'^' ( 94) |11111111|111100 */ {0x3ffc,14}, - /*'_' ( 95) |100010 */ {0x22, 6}, - /*'`' ( 96) |11111111|1111101 */ {0x7ffd,15}, - /*'a' ( 97) |00011 */ {0x3, 5}, - /*'b' ( 98) |100011 */ {0x23, 6}, - /*'c' ( 99) |00100 */ {0x4, 5}, - /*'d' (100) |100100 */ {0x24, 6}, - /*'e' (101) |00101 */ {0x5, 5}, - /*'f' (102) |100101 */ {0x25, 6}, - /*'g' (103) |100110 */ {0x26, 6}, - /*'h' (104) |100111 */ {0x27, 6}, - /*'i' (105) |00110 */ {0x6, 5}, - /*'j' (106) |1110100 */ {0x74, 7}, - /*'k' (107) |1110101 */ {0x75, 7}, - /*'l' (108) |101000 */ {0x28, 6}, - /*'m' (109) |101001 */ {0x29, 6}, - /*'n' (110) |101010 */ {0x2a, 6}, - /*'o' (111) |00111 */ {0x7, 5}, - /*'p' (112) |101011 */ {0x2b, 6}, - /*'q' (113) |1110110 */ {0x76, 7}, - /*'r' (114) |101100 */ {0x2c, 6}, - /*'s' (115) |01000 */ {0x8, 5}, - /*'t' (116) |01001 */ {0x9, 5}, - /*'u' (117) |101101 */ {0x2d, 6}, - /*'v' (118) |1110111 */ {0x77, 7}, - /*'w' (119) |1111000 */ {0x78, 7}, - /*'x' (120) |1111001 */ {0x79, 7}, - /*'y' (121) |1111010 */ {0x7a, 7}, - /*'z' (122) |1111011 */ {0x7b, 7}, - /*'{' (123) |11111111|1111110 */ {0x7ffe,15}, - /*'|' (124) |11111111|100 */ {0x7fc,11}, - /*'}' (125) |11111111|111101 */ {0x3ffd,14}, - /*'~' (126) |11111111|11101 */ {0x1ffd,13}, - /* (127) |11111111|11111111|11111111|1100 */ {0xffffffc,28}, - /* (128) |11111111|11111110|0110 */ {0xfffe6,20}, - /* (129) |11111111|11111111|010010 */ {0x3fffd2,22}, - /* (130) |11111111|11111110|0111 */ {0xfffe7,20}, - /* (131) |11111111|11111110|1000 */ {0xfffe8,20}, - /* (132) |11111111|11111111|010011 */ {0x3fffd3,22}, - /* (133) |11111111|11111111|010100 */ {0x3fffd4,22}, - /* (134) |11111111|11111111|010101 */ {0x3fffd5,22}, - /* (135) |11111111|11111111|1011001 */ {0x7fffd9,23}, - /* (136) |11111111|11111111|010110 */ {0x3fffd6,22}, - /* (137) |11111111|11111111|1011010 */ {0x7fffda,23}, - /* (138) |11111111|11111111|1011011 */ {0x7fffdb,23}, - /* (139) |11111111|11111111|1011100 */ {0x7fffdc,23}, - /* (140) |11111111|11111111|1011101 */ {0x7fffdd,23}, - /* (141) |11111111|11111111|1011110 */ {0x7fffde,23}, - /* (142) |11111111|11111111|11101011 */ {0xffffeb,24}, - /* (143) |11111111|11111111|1011111 */ {0x7fffdf,23}, - /* (144) |11111111|11111111|11101100 */ {0xffffec,24}, - /* (145) |11111111|11111111|11101101 */ {0xffffed,24}, - /* (146) |11111111|11111111|010111 */ {0x3fffd7,22}, - /* (147) |11111111|11111111|1100000 */ {0x7fffe0,23}, - /* (148) |11111111|11111111|11101110 */ {0xffffee,24}, - /* (149) |11111111|11111111|1100001 */ {0x7fffe1,23}, - /* (150) |11111111|11111111|1100010 */ {0x7fffe2,23}, - /* (151) |11111111|11111111|1100011 */ {0x7fffe3,23}, - /* (152) |11111111|11111111|1100100 */ {0x7fffe4,23}, - /* (153) |11111111|11111110|11100 */ {0x1fffdc,21}, - /* (154) |11111111|11111111|011000 */ {0x3fffd8,22}, - /* (155) |11111111|11111111|1100101 */ {0x7fffe5,23}, - /* (156) |11111111|11111111|011001 */ {0x3fffd9,22}, - /* (157) |11111111|11111111|1100110 */ {0x7fffe6,23}, - /* (158) |11111111|11111111|1100111 */ {0x7fffe7,23}, - /* (159) |11111111|11111111|11101111 */ {0xffffef,24}, - /* (160) |11111111|11111111|011010 */ {0x3fffda,22}, - /* (161) |11111111|11111110|11101 */ {0x1fffdd,21}, - /* (162) |11111111|11111110|1001 */ {0xfffe9,20}, - /* (163) |11111111|11111111|011011 */ {0x3fffdb,22}, - /* (164) |11111111|11111111|011100 */ {0x3fffdc,22}, - /* (165) |11111111|11111111|1101000 */ {0x7fffe8,23}, - /* (166) |11111111|11111111|1101001 */ {0x7fffe9,23}, - /* (167) |11111111|11111110|11110 */ {0x1fffde,21}, - /* (168) |11111111|11111111|1101010 */ {0x7fffea,23}, - /* (169) |11111111|11111111|011101 */ {0x3fffdd,22}, - /* (170) |11111111|11111111|011110 */ {0x3fffde,22}, - /* (171) |11111111|11111111|11110000 */ {0xfffff0,24}, - /* (172) |11111111|11111110|11111 */ {0x1fffdf,21}, - /* (173) |11111111|11111111|011111 */ {0x3fffdf,22}, - /* (174) |11111111|11111111|1101011 */ {0x7fffeb,23}, - /* (175) |11111111|11111111|1101100 */ {0x7fffec,23}, - /* (176) |11111111|11111111|00000 */ {0x1fffe0,21}, - /* (177) |11111111|11111111|00001 */ {0x1fffe1,21}, - /* (178) |11111111|11111111|100000 */ {0x3fffe0,22}, - /* (179) |11111111|11111111|00010 */ {0x1fffe2,21}, - /* (180) |11111111|11111111|1101101 */ {0x7fffed,23}, - /* (181) |11111111|11111111|100001 */ {0x3fffe1,22}, - /* (182) |11111111|11111111|1101110 */ {0x7fffee,23}, - /* (183) |11111111|11111111|1101111 */ {0x7fffef,23}, - /* (184) |11111111|11111110|1010 */ {0xfffea,20}, - /* (185) |11111111|11111111|100010 */ {0x3fffe2,22}, - /* (186) |11111111|11111111|100011 */ {0x3fffe3,22}, - /* (187) |11111111|11111111|100100 */ {0x3fffe4,22}, - /* (188) |11111111|11111111|1110000 */ {0x7ffff0,23}, - /* (189) |11111111|11111111|100101 */ {0x3fffe5,22}, - /* (190) |11111111|11111111|100110 */ {0x3fffe6,22}, - /* (191) |11111111|11111111|1110001 */ {0x7ffff1,23}, - /* (192) |11111111|11111111|11111000|00 */ {0x3ffffe0,26}, - /* (193) |11111111|11111111|11111000|01 */ {0x3ffffe1,26}, - /* (194) |11111111|11111110|1011 */ {0xfffeb,20}, - /* (195) |11111111|11111110|001 */ {0x7fff1,19}, - /* (196) |11111111|11111111|100111 */ {0x3fffe7,22}, - /* (197) |11111111|11111111|1110010 */ {0x7ffff2,23}, - /* (198) |11111111|11111111|101000 */ {0x3fffe8,22}, - /* (199) |11111111|11111111|11110110|0 */ {0x1ffffec,25}, - /* (200) |11111111|11111111|11111000|10 */ {0x3ffffe2,26}, - /* (201) |11111111|11111111|11111000|11 */ {0x3ffffe3,26}, - /* (202) |11111111|11111111|11111001|00 */ {0x3ffffe4,26}, - /* (203) |11111111|11111111|11111011|110 */ {0x7ffffde,27}, - /* (204) |11111111|11111111|11111011|111 */ {0x7ffffdf,27}, - /* (205) |11111111|11111111|11111001|01 */ {0x3ffffe5,26}, - /* (206) |11111111|11111111|11110001 */ {0xfffff1,24}, - /* (207) |11111111|11111111|11110110|1 */ {0x1ffffed,25}, - /* (208) |11111111|11111110|010 */ {0x7fff2,19}, - /* (209) |11111111|11111111|00011 */ {0x1fffe3,21}, - /* (210) |11111111|11111111|11111001|10 */ {0x3ffffe6,26}, - /* (211) |11111111|11111111|11111100|000 */ {0x7ffffe0,27}, - /* (212) |11111111|11111111|11111100|001 */ {0x7ffffe1,27}, - /* (213) |11111111|11111111|11111001|11 */ {0x3ffffe7,26}, - /* (214) |11111111|11111111|11111100|010 */ {0x7ffffe2,27}, - /* (215) |11111111|11111111|11110010 */ {0xfffff2,24}, - /* (216) |11111111|11111111|00100 */ {0x1fffe4,21}, - /* (217) |11111111|11111111|00101 */ {0x1fffe5,21}, - /* (218) |11111111|11111111|11111010|00 */ {0x3ffffe8,26}, - /* (219) |11111111|11111111|11111010|01 */ {0x3ffffe9,26}, - /* (220) |11111111|11111111|11111111|1101 */ {0xffffffd,28}, - /* (221) |11111111|11111111|11111100|011 */ {0x7ffffe3,27}, - /* (222) |11111111|11111111|11111100|100 */ {0x7ffffe4,27}, - /* (223) |11111111|11111111|11111100|101 */ {0x7ffffe5,27}, - /* (224) |11111111|11111110|1100 */ {0xfffec,20}, - /* (225) |11111111|11111111|11110011 */ {0xfffff3,24}, - /* (226) |11111111|11111110|1101 */ {0xfffed,20}, - /* (227) |11111111|11111111|00110 */ {0x1fffe6,21}, - /* (228) |11111111|11111111|101001 */ {0x3fffe9,22}, - /* (229) |11111111|11111111|00111 */ {0x1fffe7,21}, - /* (230) |11111111|11111111|01000 */ {0x1fffe8,21}, - /* (231) |11111111|11111111|1110011 */ {0x7ffff3,23}, - /* (232) |11111111|11111111|101010 */ {0x3fffea,22}, - /* (233) |11111111|11111111|101011 */ {0x3fffeb,22}, - /* (234) |11111111|11111111|11110111|0 */ {0x1ffffee,25}, - /* (235) |11111111|11111111|11110111|1 */ {0x1ffffef,25}, - /* (236) |11111111|11111111|11110100 */ {0xfffff4,24}, - /* (237) |11111111|11111111|11110101 */ {0xfffff5,24}, - /* (238) |11111111|11111111|11111010|10 */ {0x3ffffea,26}, - /* (239) |11111111|11111111|1110100 */ {0x7ffff4,23}, - /* (240) |11111111|11111111|11111010|11 */ {0x3ffffeb,26}, - /* (241) |11111111|11111111|11111100|110 */ {0x7ffffe6,27}, - /* (242) |11111111|11111111|11111011|00 */ {0x3ffffec,26}, - /* (243) |11111111|11111111|11111011|01 */ {0x3ffffed,26}, - /* (244) |11111111|11111111|11111100|111 */ {0x7ffffe7,27}, - /* (245) |11111111|11111111|11111101|000 */ {0x7ffffe8,27}, - /* (246) |11111111|11111111|11111101|001 */ {0x7ffffe9,27}, - /* (247) |11111111|11111111|11111101|010 */ {0x7ffffea,27}, - /* (248) |11111111|11111111|11111101|011 */ {0x7ffffeb,27}, - /* (249) |11111111|11111111|11111111|1110 */ {0xffffffe,28}, - /* (250) |11111111|11111111|11111101|100 */ {0x7ffffec,27}, - /* (251) |11111111|11111111|11111101|101 */ {0x7ffffed,27}, - /* (252) |11111111|11111111|11111101|110 */ {0x7ffffee,27}, - /* (253) |11111111|11111111|11111101|111 */ {0x7ffffef,27}, - /* (254) |11111111|11111111|11111110|000 */ {0x7fffff0,27}, - /* (255) |11111111|11111111|11111011|10 */ {0x3ffffee,26}, - /*EOS (256) |11111111|11111111|11111111|111111 */ {0x3fffffff,30}, - }; - - static final int[][] LCCODES = new int[CODES.length][]; - - // Huffman decode tree stored in a flattened char array for good - // locality of reference. - static final char[] tree; - static final char[] rowsym; - static final byte[] rowbits; - - // Build the Huffman lookup tree and LC TABLE - static - { - System.arraycopy(CODES,0,LCCODES,0,CODES.length); - for (int i='A';i<='Z';i++) - LCCODES[i]=LCCODES['a'+i-'A']; - - int r=0; - for (int i=0;i 8) - { - len -= 8; - int i = ((code >>> len) & 0xFF); - - int t=current*256+i; - current = tree[t]; - if (current == 0) - { - tree[t] = (char)++r; - current=r; - } - } - - int terminal = ++r; - rowsym[r]=(char)sym; - int b = len & 0x07; - int terminalBits = b == 0?8:b; - - rowbits[r]=(byte)terminalBits; - int shift = 8 - len; - int start = current*256 + ((code << shift) & 0xFF); - int end = start + (1<= 8) - { - int c = (current >>> (bits - 8)) & 0xFF; - node = tree[node*256+c]; - if (rowbits[node]!=0) - { - // terminal node - out.append(rowsym[node]); - bits -= rowbits[node]; - node = 0; - } - else - { - // non-terminal node - bits -= 8; - } - } - } - - while (bits > 0) - { - int c = (current << (8 - bits)) & 0xFF; - node = tree[node*256+c]; - if (rowbits[node]==0 || rowbits[node] > bits) - break; - - if (rowbits[node]==0) - throw new IllegalStateException(); - - out.append(rowsym[node]); - bits -= rowbits[node]; - node = 0; - } - - return out.toString(); - } - - public static int octetsNeeded(String s) - { - return octetsNeeded(CODES,s); - } - - public static void encode(ByteBuffer buffer,String s) - { - encode(CODES,buffer,s); - } - - public static int octetsNeededLC(String s) - { - return octetsNeeded(LCCODES,s); - } - - public static void encodeLC(ByteBuffer buffer, String s) - { - encode(LCCODES,buffer,s); - } - - private static int octetsNeeded(final int[][] table,String s) - { - int needed=0; - int len = s.length(); - for (int i=0;i=128 || c<' ') - throw new IllegalArgumentException(); - needed += table[c][1]; - } - - return (needed+7) / 8; - } - - private static void encode(final int[][] table,ByteBuffer buffer,String s) - { - long current = 0; - int n = 0; - - byte[] array = buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - - int len = s.length(); - for (int i=0;i=128 || c<' ') - throw new IllegalArgumentException(); - int code = table[c][0]; - int bits = table[c][1]; - - current <<= bits; - current |= code; - n += bits; - - while (n >= 8) - { - n -= 8; - array[p++]=(byte)(current >> n); - } - } - - if (n > 0) - { - current <<= (8 - n); - current |= (0xFF >>> n); - array[p++]=(byte)current; - } - - buffer.position(p-buffer.arrayOffset()); - } - -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java deleted file mode 100644 index 1db32e3a1ef..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ /dev/null @@ -1,184 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http2.hpack; - - -import org.eclipse.jetty.http.BadMessageException; -import org.eclipse.jetty.http.HostPortHttpField; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.http.MetaData; - -public class MetaDataBuilder -{ - private final int _maxSize; - private int _size; - private int _status; - private String _method; - private HttpScheme _scheme; - private HostPortHttpField _authority; - private String _path; - private long _contentLength=Long.MIN_VALUE; - - private HttpFields _fields = new HttpFields(10); - - /* ------------------------------------------------------------ */ - /** - * @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters. - */ - MetaDataBuilder(int maxHeadersSize) - { - _maxSize=maxHeadersSize; - } - - /** Get the maxSize. - * @return the maxSize - */ - public int getMaxSize() - { - return _maxSize; - } - - /** Get the size. - * @return the current size in bytes - */ - public int getSize() - { - return _size; - } - - public void emit(HttpField field) - { - int field_size = field.getName().length()+field.getValue().length(); - _size+=field_size; - if (_size>_maxSize) - throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize); - - if (field instanceof StaticTableHttpField) - { - StaticTableHttpField value = (StaticTableHttpField)field; - switch(field.getHeader()) - { - case C_STATUS: - _status=(Integer)value.getStaticValue(); - break; - - case C_METHOD: - _method=field.getValue(); - break; - - case C_SCHEME: - _scheme = (HttpScheme)value.getStaticValue(); - break; - - default: - throw new IllegalArgumentException(field.getName()); - } - } - else if (field.getHeader()!=null) - { - switch(field.getHeader()) - { - case C_STATUS: - _status=field.getIntValue(); - break; - - case C_METHOD: - _method=field.getValue(); - break; - - case C_SCHEME: - _scheme = HttpScheme.CACHE.get(field.getValue()); - break; - - case C_AUTHORITY: - _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); - break; - - case HOST: - // :authority fields must come first. If we have one, ignore the host header as far as authority goes. - if (_authority==null) - _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); - _fields.add(field); - break; - - case C_PATH: - _path = field.getValue(); - break; - - case CONTENT_LENGTH: - _contentLength = field.getLongValue(); - _fields.add(field); - break; - - default: - if (field.getName().charAt(0)!=':') - _fields.add(field); - } - } - else - { - if (field.getName().charAt(0)!=':') - _fields.add(field); - } - } - - public MetaData build() - { - try - { - HttpFields fields = _fields; - _fields = new HttpFields(Math.max(10,fields.size()+5)); - - if (_method!=null) - return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength); - if (_status!=0) - return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength); - return new MetaData(HttpVersion.HTTP_2,fields,_contentLength); - } - finally - { - _status=0; - _method=null; - _scheme=null; - _authority=null; - _path=null; - _size=0; - _contentLength=Long.MIN_VALUE; - } - } - - /* ------------------------------------------------------------ */ - /** Check that the max size will not be exceeded. - * @param length the length - * @param huffman the huffman name - */ - public void checkSize(int length, boolean huffman) - { - // Apply a huffman fudge factor - if (huffman) - length=(length*4)/3; - if ((_size+length)>_maxSize) - throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize); - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/NBitInteger.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/NBitInteger.java deleted file mode 100644 index 5e991173dc0..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/NBitInteger.java +++ /dev/null @@ -1,151 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -public class NBitInteger -{ - public static int octectsNeeded(int n,int i) - { - if (n==8) - { - int nbits = 0xFF; - i=i-nbits; - if (i<0) - return 1; - if (i==0) - return 2; - int lz=Integer.numberOfLeadingZeros(i); - int log=32-lz; - return 1+(log+6)/7; - } - - int nbits = 0xFF >>> (8 - n); - i=i-nbits; - if (i<0) - return 0; - if (i==0) - return 1; - int lz=Integer.numberOfLeadingZeros(i); - int log=32-lz; - return (log+6)/7; - } - - public static void encode(ByteBuffer buf, int n, int i) - { - if (n==8) - { - if (i < 0xFF) - { - buf.put((byte)i); - } - else - { - buf.put((byte)0xFF); - - int length = i - 0xFF; - while (true) - { - if ((length & ~0x7F) == 0) - { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; - } - } - } - } - else - { - int p=buf.position()-1; - int bits = 0xFF >>> (8 - n); - - if (i < bits) - { - buf.put(p,(byte)((buf.get(p)&~bits)|i)); - } - else - { - buf.put(p,(byte)(buf.get(p)|bits)); - - int length = i - bits; - while (true) - { - if ((length & ~0x7F) == 0) - { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; - } - } - } - } - } - - public static int decode(ByteBuffer buffer, int n) - { - if (n==8) - { - int nbits = 0xFF; - - int i=buffer.get()&0xff; - - if (i == nbits) - { - int m=1; - int b; - do - { - b = 0xff&buffer.get(); - i = i + (b&127) * m; - m = m*128; - } - while ((b&128) == 128); - } - return i; - } - - int nbits = 0xFF >>> (8 - n); - - int i=buffer.get(buffer.position()-1)&nbits; - - if (i == nbits) - { - int m=1; - int b; - do - { - b = 0xff&buffer.get(); - i = i + (b&127) * m; - m = m*128; - } - while ((b&128) == 128); - } - return i; - } -} diff --git a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java b/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java deleted file mode 100644 index 275ab53629c..00000000000 --- a/org.eclipse.jetty.http/src/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.http2.hpack; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; - -/* ------------------------------------------------------------ */ -public class StaticTableHttpField extends HttpField -{ - private final Object _value; - - public StaticTableHttpField(HttpHeader header, String name, String valueString, Object value) - { - super(header,name,valueString); - if (value==null) - throw new IllegalArgumentException(); - _value=value; - } - - public StaticTableHttpField(HttpHeader header,String valueString, Object value) - { - this (header,header.asString(),valueString, value); - } - - public StaticTableHttpField(String name, String valueString, Object value) - { - super(name,valueString); - if (value==null) - throw new IllegalArgumentException(); - _value=value; - } - - public Object getStaticValue() - { - return _value; - } - - @Override - public String toString() - { - return super.toString()+"(evaluated)"; - } -} \ No newline at end of file