1 jls.loader.provide('jls.net.http.HttpHeader');
  2 
  3 jls.loader.require('jls.lang.ByteBuffer');
  4 jls.loader.require('jls.net.URL');
  5 jls.loader.require('jls.net.SelectionHandler');
  6 
  7 /*
  8 see http://tools.ietf.org/html/rfc2068
  9 
 10 HTTP-message    = Request | Response     ; HTTP/1.1 messages
 11 generic-message = start-line
 12                  *message-header
 13                  CRLF
 14                  [ message-body ]
 15 start-line      = Request-Line | Status-Line
 16 
 17 If a Content-Length header field (section 14.14) is present, its
 18 value in bytes represents the length of the message-body.
 19 
 20 two classes request - response that can write - read http
 21 a handler is called when read is done
 22 */
 23 
 24 jls.net.http.HttpHeader = jls.lang.Class.create(jls.net.SelectionHandler, /** @lends jls.net.http.HttpHeader.prototype */
 25 {
 26     /**
 27      * Creates an HTTP header.
 28      *
 29      * @param {String} [startLine] The start line.
 30      * @param {Object} [fields] The fields.
 31      * @constructs
 32 	 * @augments jls.net.SelectionHandler
 33 	 * @class This class represents an HTTP header.
 34      */
 35     initialize : function(startLine, fields) {
 36         this._startLine = '';
 37         this._fields = {};
 38         if (startLine) {
 39             this.setStartLine(startLine);
 40         }
 41         if (fields) {
 42             for (var k in fields) {
 43                 this.setField(k, fields[k]);
 44             }
 45         }
 46         this._hdrStr = null;
 47         this._buffer = null;
 48     },
 49     clear : function() {
 50         this._startLine = '';
 51         this._fields = {};
 52     },
 53     getStartLine : function() {
 54         return this._startLine;
 55     },
 56     setStartLine : function(startLine) {
 57         this._startLine = startLine;
 58         return this;
 59     },
 60     getField : function(key) {
 61         return this._fields[key];
 62     },
 63     setField : function(key, value) {
 64         this._fields[key] = value;
 65         return this;
 66     },
 67     getContentLength : function() {
 68         return this.getField(jls.net.http.HttpHeader.HEADER_CONTENT_LENGTH) || 0;
 69     },
 70     /*length : function() {
 71         return this._buffer.capacity();
 72     },*/
 73     reset : function() {
 74         if (this._buffer != null) {
 75             this._buffer.clear();
 76         }
 77         return this;
 78     },
 79     /*
 80      * TODO Use jls.net.BufferSelectionHandler for R/W
 81      */
 82     onRead : function(input) {
 83         jls.logger.debug('onRead()');
 84         if (this._hdrStr == null) {
 85             this._hdrStr = '';
 86             // clear header
 87             this._startLine = '';
 88             this._fields = {};
 89         }
 90         var b = input.readByte();
 91         if (b < 0) {
 92             jls.logger.debug('b = ' + b);
 93             return -1; // cannot read
 94         }
 95         for (; b >= 0; b = input.readByte()) {
 96             jls.logger.debug('b = ' + b);
 97             this._hdrStr += String.fromCharCode(b);
 98             //jls.logger.debug('header part: ->' + this._hdrStr + '<-');
 99             if (this._hdrStr.substr(-4) == '\r\n\r\n') {
100                 this.fromString(this._hdrStr);
101                 this._hdrStr = null;
102                 return 1; // completed
103             }
104         }
105         return 0; // in progress
106     },
107     onWrite : function(output) {
108         if (this._buffer == null) {
109             this._buffer = jls.lang.ByteBuffer.fromString(this.toString());
110         }
111         if (output.write(this._buffer) == 0) {
112             return -1; // cannot write
113         }
114         if (this._buffer.remaining() == 0) {
115             this._buffer.clear();
116             return 1; // completed
117         }
118         return 0; // in progress
119     },
120     fromString : function(s) {
121         var lines = s.split(jls.net.http.HttpHeader.lineSeparator);
122         var startLine = lines[0];
123         jls.logger.trace('set(parse) start line');
124         this.setStartLine(startLine);
125         for (var i = 1; i < lines.length; i++) {
126             var entry = lines[i].split(/\s*:\s*/);
127             if (entry.length != 2) {
128                 // TODO Throw something ?
129                 continue;
130             }
131             this.setField(entry[0], entry[1]);
132         }
133         return this;
134     },
135     toString : function() {
136         var header = this.getStartLine() + jls.net.http.HttpHeader.lineSeparator;
137         for (var k in this._fields) {
138             header += k + ': ' + this._fields[k] + jls.net.http.HttpHeader.lineSeparator;
139         }
140         header += jls.net.http.HttpHeader.lineSeparator;
141         return header;
142     }
143 });
144 
145 Object.extend(jls.net.http.HttpHeader, /** @lends jls.net.http.HttpHeader */
146 {
147     fromString : function(s) {
148         var hdr = s.startsWith(jls.net.http.HttpHeader.VERSION_PREFIX) ? new jls.net.http.HttpResponseHeader() : new jls.net.http.HttpRequestHeader();
149         hdr.fromString(s);
150         return hdr;
151     },
152     lineSeparator : '\r\n',
153     //space : ' ',
154 /*
155 100 Continue
156 101 Switching Protocols
157 200 OK
158 201 Created
159 202 Accepted
160 203 Non-Authoritative Information
161 204 No Content
162 205 Reset Content
163 206 Partial Content
164 300 Multiple Choices
165 301 Moved Permanently
166 302 Moved Temporarily
167 303 See Other
168 304 Not Modified
169 305 Use Proxy
170 400 Bad Request
171 401 Unauthorized
172 402 Payment Required
173 403 Forbidden
174 404 Not Found
175 405 Method Not Allowed
176 406 Not Acceptable
177 407 Proxy Authentication Required
178 408 Request Time-out
179 409 Conflict
180 410 Gone
181 411 Length Required
182 412 Precondition Failed
183 413 Request Entity Too Large
184 414 Request-URI Too Large
185 415 Unsupported Media Type
186 500 Internal Server Error
187 501 Not Implemented
188 502 Bad Gateway
189 503 Service Unavailable
190 504 Gateway Time-out
191 505 HTTP Version not supported
192 */
193     HTTP_OK : 200,
194     HTTP_NOT_FOUND : 404,
195 
196 /*
197 OPTIONS
198 GET
199 HEAD
200 POST
201 PUT
202 DELETE
203 TRACE
204 */
205     METHOD_GET : 'GET',
206     METHOD_POST : 'POST',
207 
208 /*
209 There are two major versions, HTTP/1.0 that uses a separate connection for every document and
210 HTTP/1.1 that can reuse the same connection to download, for instance, images for the just served page.
211 Hence HTTP/1.1 may be faster as it takes time to set up such connections.
212 */
213     VERSION_PREFIX : 'HTTP/', // TODO Rename as Protocol?
214     VERSION_1_0 : '1.0',
215     VERSION_1_1 : '1.1',
216 
217     DEFAULT_USER_AGENT: 'JLS',
218 
219     HEADER_HOST: 'Host',
220     HEADER_USER_AGENT: 'User-Agent',
221     HEADER_ACCEPT: 'Accept',
222     HEADER_ACCEPT_LANGUAGE: 'Accept-Language',
223     HEADER_ACCEPT_ENCODING: 'Accept-Encoding',
224     HEADER_ACCEPT_CHARSET: 'Accept-Charset',
225     HEADER_KEEP_ALIVE: 'Keep-Alive',
226     HEADER_PROXY_CONNECTION: 'Proxy-Connection',
227     HEADER_COOKIE: 'Cookie',
228     HEADER_CONTENT_LENGTH: 'Content-Length',
229     HEADER_CONTENT_TYPE: 'Content-Type'
230     
231 });
232 
233