diff options
author | Jose <jose@zeroc.com> | 2014-08-12 20:46:07 +0200 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2014-08-12 20:46:07 +0200 |
commit | a31393f368bc78281179e0e2c0ac2a37f7b849c1 (patch) | |
tree | a9b8ba6e228142bb522c976a766f41349b502bff /java/src/IceInternal/HttpParser.java | |
parent | Added eclipse project settings for java. (diff) | |
download | ice-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.java | 735 |
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; +} |