summaryrefslogtreecommitdiff
path: root/java/src/IceInternal/HttpParser.java
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2014-08-12 20:46:07 +0200
committerJose <jose@zeroc.com>2014-08-12 20:46:07 +0200
commita31393f368bc78281179e0e2c0ac2a37f7b849c1 (patch)
treea9b8ba6e228142bb522c976a766f41349b502bff /java/src/IceInternal/HttpParser.java
parentAdded eclipse project settings for java. (diff)
downloadice-a31393f368bc78281179e0e2c0ac2a37f7b849c1.tar.bz2
ice-a31393f368bc78281179e0e2c0ac2a37f7b849c1.tar.xz
ice-a31393f368bc78281179e0e2c0ac2a37f7b849c1.zip
Fixed (ICE-5586) - Integrate IceWS to the Ice core library
Diffstat (limited to 'java/src/IceInternal/HttpParser.java')
-rw-r--r--java/src/IceInternal/HttpParser.java735
1 files changed, 735 insertions, 0 deletions
diff --git a/java/src/IceInternal/HttpParser.java b/java/src/IceInternal/HttpParser.java
new file mode 100644
index 00000000000..b5567b080b6
--- /dev/null
+++ b/java/src/IceInternal/HttpParser.java
@@ -0,0 +1,735 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+final class HttpParser
+{
+ HttpParser()
+ {
+ _type = Type.Unknown;
+ _versionMajor = 0;
+ _versionMinor = 0;
+ _status = 0;
+ _state = State.Init;
+ }
+
+ enum Type
+ {
+ Unknown,
+ Request,
+ Response
+ };
+
+ int isCompleteMessage(java.nio.ByteBuffer buf, int begin, int end)
+ {
+ int p = begin;
+
+ //
+ // Skip any leading CR-LF characters.
+ //
+ while(p < end)
+ {
+ byte ch = buf.get(p);
+ if(ch != (byte)'\r' && ch != (byte)'\n')
+ {
+ break;
+ }
+ ++p;
+ }
+
+ //
+ // Look for adjacent CR-LF/CR-LF or LF/LF.
+ //
+ boolean seenFirst = false;
+ while(p < end)
+ {
+ byte ch = buf.get(p++);
+ if(ch == (byte)'\n')
+ {
+ if(seenFirst)
+ {
+ return p;
+ }
+ else
+ {
+ seenFirst = true;
+ }
+ }
+ else if(ch != (byte)'\r')
+ {
+ seenFirst = false;
+ }
+ }
+
+ return -1;
+ }
+
+ boolean parse(java.nio.ByteBuffer buf, int begin, int end)
+ {
+ int p = begin;
+ int start = 0;
+ final char CR = '\r';
+ final char LF = '\n';
+
+ if(_state == State.Complete)
+ {
+ _state = State.Init;
+ }
+
+ while(p != end && _state != State.Complete)
+ {
+ char c = (char)buf.get(p);
+
+ switch(_state)
+ {
+ case Init:
+ {
+ _method.setLength(0);
+ _uri.setLength(0);
+ _versionMajor = -1;
+ _versionMinor = -1;
+ _status = -1;
+ _reason = "";
+ _headers.clear();
+ _state = State.Type;
+ continue;
+ }
+ case Type:
+ {
+ if(c == CR || c == LF)
+ {
+ break;
+ }
+ else if(c == 'H')
+ {
+ //
+ // Could be the start of "HTTP/1.1" or "HEAD".
+ //
+ _state = State.TypeCheck;
+ break;
+ }
+ else
+ {
+ _state = State.Request;
+ continue;
+ }
+ }
+ case TypeCheck:
+ {
+ if(c == 'T') // Continuing "H_T_TP/1.1"
+ {
+ _state = State.Response;
+ }
+ else if(c == 'E') // Expecting "HEAD"
+ {
+ _state = State.Request;
+ _method.append('H');
+ _method.append('E');
+ }
+ else
+ {
+ throw new WebSocketException("malformed request or response");
+ }
+ break;
+ }
+ case Request:
+ {
+ _type = Type.Request;
+ _state = State.RequestMethod;
+ continue;
+ }
+ case RequestMethod:
+ {
+ if(c == ' ' || c == CR || c == LF)
+ {
+ _state = State.RequestMethodSP;
+ continue;
+ }
+ _method.append(c);
+ break;
+ }
+ case RequestMethodSP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.RequestURI;
+ continue;
+ }
+ case RequestURI:
+ {
+ if(c == ' ' || c == CR || c == LF)
+ {
+ _state = State.RequestURISP;
+ continue;
+ }
+ _uri.append(c);
+ break;
+ }
+ case RequestURISP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.Version;
+ continue;
+ }
+ case RequestLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case HeaderFieldStart:
+ {
+ //
+ // We've already seen a LF to reach this state.
+ //
+ // Another CR or LF indicates the end of the header fields.
+ //
+ if(c == CR)
+ {
+ _state = State.HeaderFieldEndLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ _state = State.Complete;
+ break;
+ }
+ else if(c == ' ')
+ {
+ //
+ // Could be a continuation line.
+ //
+ _state = State.HeaderFieldContStart;
+ break;
+ }
+
+ _state = State.HeaderFieldNameStart;
+ continue;
+ }
+ case HeaderFieldContStart:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.HeaderFieldCont;
+ start = p;
+ continue;
+ }
+ case HeaderFieldCont:
+ {
+ if(c == CR || c == LF)
+ {
+ if(p > start)
+ {
+ if(_headerName.length() == 0)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ String s = _headers.get(_headerName);
+ assert(s != null);
+ StringBuffer newValue = new StringBuffer(s);
+ newValue.append(' ');
+ for(int i = start; i < p; ++i)
+ {
+ newValue.append((char)buf.get(i));
+ }
+ _headers.put(_headerName, newValue.toString());
+ _state = c == CR ? State.HeaderFieldLF : State.HeaderFieldStart;
+ }
+ else
+ {
+ //
+ // Could mark the end of the header fields.
+ //
+ _state = c == CR ? State.HeaderFieldEndLF : State.Complete;
+ }
+ }
+
+ break;
+ }
+ case HeaderFieldNameStart:
+ {
+ assert(c != ' ');
+ start = p;
+ _headerName = "";
+ _state = State.HeaderFieldName;
+ continue;
+ }
+ case HeaderFieldName:
+ {
+ if(c == ' ' || c == ':')
+ {
+ _state = State.HeaderFieldNameEnd;
+ continue;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ break;
+ }
+ case HeaderFieldNameEnd:
+ {
+ if(_headerName.length() == 0)
+ {
+ StringBuffer str = new StringBuffer();
+ for(int i = start; i < p; ++i)
+ {
+ str.append((char)buf.get(i));
+ }
+ _headerName = str.toString().toLowerCase();
+ //
+ // Add a placeholder entry if necessary.
+ //
+ if(!_headers.containsKey(_headerName))
+ {
+ _headers.put(_headerName, "");
+ }
+ }
+
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c != ':' || p == start)
+ {
+ throw new WebSocketException("malformed header");
+ }
+
+ _state = State.HeaderFieldValueStart;
+ break;
+ }
+ case HeaderFieldValueStart:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ //
+ // Check for "Name:\r\n"
+ //
+ if(c == CR)
+ {
+ _state = State.HeaderFieldLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ _state = State.HeaderFieldStart;
+ break;
+ }
+
+ start = p;
+ _state = State.HeaderFieldValue;
+ continue;
+ }
+ case HeaderFieldValue:
+ {
+ if(c == CR || c == LF)
+ {
+ _state = State.HeaderFieldValueEnd;
+ continue;
+ }
+ break;
+ }
+ case HeaderFieldValueEnd:
+ {
+ assert(c == CR || c == LF);
+ if(p > start)
+ {
+ StringBuffer str = new StringBuffer();
+ for(int i = start; i < p; ++i)
+ {
+ str.append((char)buf.get(i));
+ }
+ String s = _headers.get(_headerName);
+ if(s == null || s.length() == 0)
+ {
+ _headers.put(_headerName, str.toString());
+ }
+ else
+ {
+ _headers.put(_headerName, s + ", " + str.toString());
+ }
+ }
+
+ if(c == CR)
+ {
+ _state = State.HeaderFieldLF;
+ }
+ else
+ {
+ _state = State.HeaderFieldStart;
+ }
+ break;
+ }
+ case HeaderFieldLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case HeaderFieldEndLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ _state = State.Complete;
+ break;
+ }
+ case Version:
+ {
+ if(c != 'H')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionH;
+ break;
+ }
+ case VersionH:
+ {
+ if(c != 'T')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHT;
+ break;
+ }
+ case VersionHT:
+ {
+ if(c != 'T')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHTT;
+ break;
+ }
+ case VersionHTT:
+ {
+ if(c != 'P')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHTTP;
+ break;
+ }
+ case VersionHTTP:
+ {
+ if(c != '/')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionMajor;
+ break;
+ }
+ case VersionMajor:
+ {
+ if(c == '.')
+ {
+ if(_versionMajor == -1)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionMinor;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ if(_versionMajor == -1)
+ {
+ _versionMajor = 0;
+ }
+ _versionMajor *= 10;
+ _versionMajor += c - '0';
+ break;
+ }
+ case VersionMinor:
+ {
+ if(c == CR)
+ {
+ if(_versionMinor == -1 || _type != Type.Request)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.RequestLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ if(_versionMinor == -1 || _type != Type.Request)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ else if(c == ' ')
+ {
+ if(_versionMinor == -1 || _type != Type.Response)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.ResponseVersionSP;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ if(_versionMinor == -1)
+ {
+ _versionMinor = 0;
+ }
+ _versionMinor *= 10;
+ _versionMinor += c - '0';
+ break;
+ }
+ case Response:
+ {
+ _type = Type.Response;
+ _state = State.VersionHT;
+ continue;
+ }
+ case ResponseVersionSP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.ResponseStatus;
+ continue;
+ }
+ case ResponseStatus:
+ {
+ // TODO: Is reason string optional?
+ if(c == CR)
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.ResponseLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ else if(c == ' ')
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.ResponseReasonStart;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ if(_status == -1)
+ {
+ _status = 0;
+ }
+ _status *= 10;
+ _status += c - '0';
+ break;
+ }
+ case ResponseReasonStart:
+ {
+ //
+ // Skip leading spaces.
+ //
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.ResponseReason;
+ start = p;
+ continue;
+ }
+ case ResponseReason:
+ {
+ if(c == CR || c == LF)
+ {
+ if(p > start)
+ {
+ StringBuffer str = new StringBuffer();
+ for(int i = start; i < p; ++i)
+ {
+ str.append((char)buf.get(i));
+ }
+ _reason = str.toString();
+ }
+ _state = c == CR ? State.ResponseLF : State.HeaderFieldStart;
+ }
+
+ break;
+ }
+ case ResponseLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed status line");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case Complete:
+ {
+ assert(false); // Shouldn't reach
+ }
+ }
+
+ ++p;
+ }
+
+ return _state == State.Complete;
+ }
+
+ Type type()
+ {
+ return _type;
+ }
+
+ String method()
+ {
+ assert(_type == Type.Request);
+ return _method.toString();
+ }
+
+ String uri()
+ {
+ assert(_type == Type.Request);
+ return _uri.toString();
+ }
+
+ int versionMajor()
+ {
+ return _versionMajor;
+ }
+
+ int versionMinor()
+ {
+ return _versionMinor;
+ }
+
+ int status()
+ {
+ return _status;
+ }
+
+ String reason()
+ {
+ return _reason;
+ }
+
+ String getHeader(String name, boolean toLower)
+ {
+ String s = _headers.get(name.toLowerCase());
+ if(s != null)
+ {
+ return toLower ? s.trim().toLowerCase() : s.trim();
+ }
+
+ return null;
+ }
+
+ java.util.Map<String, String> headers()
+ {
+ return _headers;
+ }
+
+ private Type _type;
+
+ private StringBuffer _method = new StringBuffer();
+ private StringBuffer _uri = new StringBuffer();
+
+ private java.util.Map<String, String> _headers = new java.util.HashMap<String, String>();
+ private String _headerName = "";
+
+ private int _versionMajor;
+ private int _versionMinor;
+
+ private int _status;
+ private String _reason;
+
+ enum State
+ {
+ Init,
+ Type,
+ TypeCheck,
+ Request,
+ RequestMethod,
+ RequestMethodSP,
+ RequestURI,
+ RequestURISP,
+ RequestLF,
+ HeaderFieldStart,
+ HeaderFieldContStart,
+ HeaderFieldCont,
+ HeaderFieldNameStart,
+ HeaderFieldName,
+ HeaderFieldNameEnd,
+ HeaderFieldValueStart,
+ HeaderFieldValue,
+ HeaderFieldValueEnd,
+ HeaderFieldLF,
+ HeaderFieldEndLF,
+ Version,
+ VersionH,
+ VersionHT,
+ VersionHTT,
+ VersionHTTP,
+ VersionMajor,
+ VersionMinor,
+ Response,
+ ResponseVersionSP,
+ ResponseStatus,
+ ResponseReasonStart,
+ ResponseReason,
+ ResponseLF,
+ Complete
+ };
+ private State _state;
+}