/** * 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. * @exception IllegalArgumentException If the name is a single valued field and already has a * value. */ public void add(Buffer name, Buffer value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException("null value"); if (!(name instanceof CachedBuffer)) name = HttpHeaders.CACHE.lookup(name); name = name.asImmutableBuffer(); if (!(value instanceof CachedBuffer) && HttpHeaderValues.hasKnownValues(HttpHeaders.CACHE.getOrdinal(name))) value = HttpHeaderValues.CACHE.lookup(value); value = value.asImmutableBuffer(); Field field = _names.get(name); Field last = null; while (field != null) { last = field; field = field._next; } // create the field field = new Field(name, value); _fields.add(field); // look for chain to add too if (last != null) last._next = field; else _names.put(name, field); }
/* ------------------------------------------------------------ */ public InputStream getInputStream() throws IOException { Buffer indirect = getIndirectBuffer(); if (indirect != null && indirect.array() != null) return new ByteArrayInputStream(indirect.array(), indirect.getIndex(), indirect.length()); return _resource.getInputStream(); }
private ByteBuffer wrap(Buffer b) { byte[] array = b.array(); if (array != null) { return ByteBuffer.wrap(array, b.getIndex(), b.length()); } else { return ByteBuffer.wrap(b.asArray(), 0, b.length()); } }
public void encode(Buffer buffer) throws IOException { for (Record record : _records) { getMessage().getCompression().encodeName(record.getName(), buffer); record.getType().encode(buffer); record.getDnsClass().encode(buffer); BufferUtil.putInt(buffer, record.getTtl()); int index = buffer.putIndex(); buffer.setPutIndex(index + 2); record.doEncode(buffer, getMessage().getCompression()); BufferUtil.poke16(buffer, index, buffer.putIndex() - index - 2); } }
public void startResponse(Buffer version, int status, Buffer reason) { request = false; f0 = version.toString(); f1 = Integer.toString(status); f2 = reason == null ? null : reason.toString(); fields = new HttpFields(); hdr = new String[9]; val = new String[9]; messageCompleted = false; headerCompleted = false; }
private synchronized int expelBuffer(long blockFor) throws IOException { if (_buffer == null) return 0; int result = flushBuffer(); _buffer.compact(); if (!_endp.isBlocking()) { while (_buffer.space() == 0) { boolean ready = _endp.blockWritable(blockFor); if (!ready) throw new IOException("Write timeout"); result += flushBuffer(); _buffer.compact(); } } return result; }
public void onFrame(byte flags, byte opcode, Buffer buffer) { try { byte[] array = buffer.array(); if (opcode == 0) { if (_websocket instanceof WebSocket.OnTextMessage) ((WebSocket.OnTextMessage) _websocket).onMessage(buffer.toString(StringUtil.__UTF8)); } else { if (_websocket instanceof WebSocket.OnBinaryMessage) ((WebSocket.OnBinaryMessage) _websocket) .onMessage(array, buffer.getIndex(), buffer.length()); } } catch (Throwable th) { LOG.warn(th); } }
private synchronized int flushBuffer() throws IOException { if (!_endp.isOpen()) throw new EofException(); if (_buffer != null && _buffer.hasContent()) return _endp.flush(_buffer); return 0; }
public synchronized int flush() throws IOException { int flushed = flushBuffer(); if (_buffer != null && _buffer.length() == 0) { _buffers.returnBuffer(_buffer); _buffer = null; } return flushed; }
/* ------------------------------------------------------------ */ protected Buffer getIndirectBuffer(Resource resource) { try { int len = (int) resource.length(); if (len < 0) { LOG.warn("invalid resource: " + String.valueOf(resource) + " " + len); return null; } Buffer buffer = new IndirectNIOBuffer(len); InputStream is = resource.getInputStream(); buffer.readFrom(is, len); is.close(); return buffer; } catch (IOException e) { LOG.warn(e); return null; } }
/* (non-Javadoc) * @see org.eclipse.jetty.websocket.AbstractExtension#onFrame(byte, byte, org.eclipse.jetty.io.Buffer) */ @Override public void onFrame(byte flags, byte opcode, Buffer buffer) { if (getConnection().isControl(opcode) || !isFlag(flags, 1)) { super.onFrame(flags, opcode, buffer); return; } if (buffer.array() == null) buffer = buffer.asMutableBuffer(); int length = 0xff & buffer.get(); if (length >= 0x7e) { int b = (length == 0x7f) ? 8 : 2; length = 0; while (b-- > 0) length = 0x100 * length + (0xff & buffer.get()); } // TODO check a max framesize _inflater.setInput(buffer.array(), buffer.getIndex(), buffer.length()); ByteArrayBuffer buf = new ByteArrayBuffer(length); try { while (_inflater.getRemaining() > 0) { int inflated = _inflater.inflate(buf.array(), buf.putIndex(), buf.space()); if (inflated == 0) throw new DataFormatException("insufficient data"); buf.setPutIndex(buf.putIndex() + inflated); } super.onFrame(clearFlag(flags, 1), opcode, buf); } catch (DataFormatException e) { LOG.warn(e); getConnection().close(WebSocketConnectionRFC6455.CLOSE_BAD_PAYLOAD, e.toString()); } }
public void startRequest(Buffer tok0, Buffer tok1, Buffer tok2) { try { request = true; h = -1; hdr = new String[9]; val = new String[9]; f0 = tok0.toString(); f1 = new String(tok1.array(), tok1.getIndex(), tok1.length(), StringUtil.__UTF8); if (tok2 != null) f2 = tok2.toString(); else f2 = null; fields = new HttpFields(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } messageCompleted = false; headerCompleted = false; }
/* * * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startRequest(org.eclipse.io.Buffer, * org.eclipse.io.Buffer, org.eclipse.io.Buffer) */ @Override public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException { uri = uri.asImmutableBuffer(); _host = false; _expect = false; _expect100Continue = false; _expect102Processing = false; _delayedHandling = false; _charset = null; if (_request.getTimeStamp() == 0) _request.setTimeStamp(System.currentTimeMillis()); _request.setMethod(method.toString()); try { _head = false; switch (HttpMethods.CACHE.getOrdinal(method)) { case HttpMethods.CONNECT_ORDINAL: _uri.parseConnect(uri.array(), uri.getIndex(), uri.length()); break; case HttpMethods.HEAD_ORDINAL: _head = true; // fall through default: _uri.parse(uri.array(), uri.getIndex(), uri.length()); } _request.setUri(_uri); if (version == null) { _request.setProtocol(HttpVersions.HTTP_0_9); _version = HttpVersions.HTTP_0_9_ORDINAL; } else { version = HttpVersions.CACHE.get(version); if (version == null) throw new HttpException(HttpStatus.BAD_REQUEST_400, null); _version = HttpVersions.CACHE.getOrdinal(version); if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL; _request.setProtocol(version.toString()); } } catch (Exception e) { LOG.debug(e); if (e instanceof HttpException) throw (HttpException) e; throw new HttpException(HttpStatus.BAD_REQUEST_400, null, e); } }
@Test public void testReuse() throws Exception { HttpFields header = new HttpFields(); Buffer n1 = new ByteArrayBuffer("name1"); Buffer va = new ByteArrayBuffer("value1"); Buffer vb = new ByteArrayBuffer(10); vb.put((byte) 'v'); vb.put((byte) 'a'); vb.put((byte) 'l'); vb.put((byte) 'u'); vb.put((byte) 'e'); vb.put((byte) '1'); header.put("name0", "value0"); header.put(n1, va); header.put("name2", "value2"); assertEquals("value0", header.getStringField("name0")); assertEquals("value1", header.getStringField("name1")); assertEquals("value2", header.getStringField("name2")); assertNull(header.getStringField("name3")); header.remove(n1); assertNull(header.getStringField("name1")); header.put(n1, vb); assertEquals("value1", header.getStringField("name1")); int matches = 0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) { Object o = e.nextElement(); if ("name0".equals(o)) matches++; if ("name1".equals(o)) matches++; if ("name2".equals(o)) matches++; } assertEquals(3, matches); e = header.getValues("name1"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1"); assertEquals(false, e.hasMoreElements()); }
public void addContent(Buffer content, boolean last) throws IOException { LOG.debug("addContent {} {}", content.length(), last); if (_noContent) { content.clear(); return; } if (content.isImmutable()) throw new IllegalArgumentException("immutable"); if (_last || _state == STATE_END) { LOG.debug("Ignoring extra content {}", content); content.clear(); return; } _last = last; if (!_endp.isOpen()) { _state = STATE_END; return; } // Handle any unfinished business? if (_content != null && _content.length() > 0) { flushBuffer(); if (_content != null && _content.length() > 0) throw new IllegalStateException("FULL"); } _content = content; _contentWritten += content.length(); // Handle the _content if (_head) { content.clear(); _content = null; } else if (!last || _buffer != null) { // Yes - so we better check we have a buffer initBuffer(); // Copy _content to buffer; int len = 0; len = _buffer.put(_content); // make sure there is space for a trailing null (???) if (len > 0 && _buffer.space() == 0) { len--; _buffer.setPutIndex(_buffer.putIndex() - 1); } LOG.debug("copied {} to buffer", len); _content.skip(len); if (_content.length() == 0) _content = null; } }
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException { long blockFor = _endp.getMaxIdleTime(); if (_buffer == null) _buffer = _buffers.getDirectBuffer(); if (_buffer.space() == 0) expelBuffer(blockFor); bufferPut(opcode, blockFor); if (isLengthFrame(opcode)) { // Send a length delimited frame // How many bytes we need for the length ? // We have 7 bits available, so log2(length) / 7 + 1 // For example, 50000 bytes is 2 8-bytes: 11000011 01010000 // but we need to write it in 3 7-bytes 0000011 0000110 1010000 // 65536 == 1 00000000 00000000 => 100 0000000 0000000 int lengthBytes = new BigInteger(String.valueOf(length)).bitLength() / 7 + 1; for (int i = lengthBytes - 1; i > 0; --i) { byte lengthByte = (byte) (0x80 | (0x7F & (length >> 7 * i))); bufferPut(lengthByte, blockFor); } bufferPut((byte) (0x7F & length), blockFor); } int remaining = length; while (remaining > 0) { int chunk = remaining < _buffer.space() ? remaining : _buffer.space(); _buffer.put(content, offset + (length - remaining), chunk); remaining -= chunk; if (_buffer.space() > 0) { if (!isLengthFrame(opcode)) _buffer.put((byte) 0xFF); // Gently flush the data, issuing a non-blocking write flushBuffer(); } else { // Forcibly flush the data, issuing a blocking write expelBuffer(blockFor); if (remaining == 0) { if (!isLengthFrame(opcode)) _buffer.put((byte) 0xFF); // Gently flush the data, issuing a non-blocking write flushBuffer(); } } } }
private synchronized void bufferPut(byte data) throws IOException { _buffer.put((byte) (data ^ _mask[+_m++ % 4])); }
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException { // System.err.printf("<< %s %s // %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length); long blockFor = _endp.getMaxIdleTime(); if (_buffer == null) _buffer = (_maskGen != null) ? _buffers.getBuffer() : _buffers.getDirectBuffer(); boolean last = WebSocketConnectionD06.isLastFrame(flags); opcode = (byte) (((0xf & flags) << 4) + 0xf & opcode); int space = (_maskGen != null) ? 14 : 10; do { opcode = _opsent ? WebSocketConnectionD06.OP_CONTINUATION : opcode; _opsent = true; int payload = length; if (payload + space > _buffer.capacity()) { // We must fragement, so clear FIN bit opcode &= (byte) 0x7F; // Clear the FIN bit payload = _buffer.capacity() - space; } else if (last) opcode |= (byte) 0x80; // Set the FIN bit // ensure there is space for header if (_buffer.space() <= space) expelBuffer(blockFor); // write mask if ((_maskGen != null)) { _maskGen.genMask(_mask); _m = 0; _buffer.put(_mask); } // write the opcode and length if (payload > 0xffff) { bufferPut( new byte[] { opcode, (byte) 0x7f, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) ((payload >> 24) & 0xff), (byte) ((payload >> 16) & 0xff), (byte) ((payload >> 8) & 0xff), (byte) (payload & 0xff) }); } else if (payload >= 0x7e) { bufferPut(new byte[] {opcode, (byte) 0x7e, (byte) (payload >> 8), (byte) (payload & 0xff)}); } else { bufferPut(opcode); bufferPut((byte) payload); } // write payload int remaining = payload; while (remaining > 0) { _buffer.compact(); int chunk = remaining < _buffer.space() ? remaining : _buffer.space(); if ((_maskGen != null)) { for (int i = 0; i < chunk; i++) bufferPut(content[offset + (payload - remaining) + i]); } else _buffer.put(content, offset + (payload - remaining), chunk); remaining -= chunk; if (_buffer.space() > 0) { // Gently flush the data, issuing a non-blocking write flushBuffer(); } else { // Forcibly flush the data, issuing a blocking write expelBuffer(blockFor); if (remaining == 0) { // Gently flush the data, issuing a non-blocking write flushBuffer(); } } } offset += payload; length -= payload; } while (length > 0); _opsent = !last; }
/* ------------------------------------------------------------ */ public Connection handle() throws IOException { try { // handle stupid hixie random bytes if (_hixieBytes != null) { // take any available bytes from the parser buffer, which may have already been read Buffer buffer = _parser.getBuffer(); if (buffer != null && buffer.length() > 0) { int l = buffer.length(); if (l > (8 - _hixieBytes.length())) l = 8 - _hixieBytes.length(); _hixieBytes.put(buffer.peek(buffer.getIndex(), l)); buffer.skip(l); } // while we are not blocked while (_endp.isOpen()) { // do we now have enough if (_hixieBytes.length() == 8) { // we have the silly random bytes // so let's work out the stupid 16 byte reply. doTheHixieHixieShake(); _endp.flush(_hixieBytes); _hixieBytes = null; _endp.flush(); break; } // no, then let's fill int filled = _endp.fill(_hixieBytes); if (filled < 0) { _endp.flush(); _endp.close(); break; } } if (_websocket instanceof OnFrame) ((OnFrame) _websocket).onHandshake(this); _websocket.onOpen(this); return this; } // handle the framing protocol boolean progress = true; while (progress) { int flushed = _generator.flush(); int filled = _parser.parseNext(); progress = flushed > 0 || filled > 0; _endp.flush(); if (_endp instanceof AsyncEndPoint && ((AsyncEndPoint) _endp).hasProgressed()) progress = true; } } catch (IOException e) { LOG.debug(e); try { if (_endp.isOpen()) _endp.close(); } catch (IOException e2) { LOG.ignore(e2); } throw e; } finally { if (_endp.isOpen()) { if (_endp.isInputShutdown() && _generator.isBufferEmpty()) _endp.close(); else checkWriteable(); checkWriteable(); } } return this; }
public synchronized boolean isBufferEmpty() { return _buffer == null || _buffer.length() == 0; }
public void parsedHeader(Buffer name, Buffer value) { hdr[++h] = name.toString(StringUtil.__ISO_8859_1); val[h] = value.toString(StringUtil.__ISO_8859_1); }
private synchronized void bufferPut(byte datum, long blockFor) throws IOException { if (_buffer == null) _buffer = _buffers.getDirectBuffer(); _buffer.put(datum); if (_buffer.space() == 0) expelBuffer(blockFor); }
/* * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#parsedHeaderValue(org.eclipse.io.Buffer) */ @Override public void parsedHeader(Buffer name, Buffer value) { int ho = HttpHeaders.CACHE.getOrdinal(name); switch (ho) { case HttpHeaders.HOST_ORDINAL: // TODO check if host matched a host in the URI. _host = true; break; case HttpHeaders.EXPECT_ORDINAL: value = HttpHeaderValues.CACHE.lookup(value); switch (HttpHeaderValues.CACHE.getOrdinal(value)) { case HttpHeaderValues.CONTINUE_ORDINAL: _expect100Continue = _generator instanceof HttpGenerator; break; case HttpHeaderValues.PROCESSING_ORDINAL: _expect102Processing = _generator instanceof HttpGenerator; break; default: String[] values = value.toString().split(","); for (int i = 0; values != null && i < values.length; i++) { CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim()); if (cb == null) _expect = true; else { switch (cb.getOrdinal()) { case HttpHeaderValues.CONTINUE_ORDINAL: _expect100Continue = _generator instanceof HttpGenerator; break; case HttpHeaderValues.PROCESSING_ORDINAL: _expect102Processing = _generator instanceof HttpGenerator; break; default: _expect = true; } } } } break; case HttpHeaders.ACCEPT_ENCODING_ORDINAL: case HttpHeaders.USER_AGENT_ORDINAL: value = HttpHeaderValues.CACHE.lookup(value); break; case HttpHeaders.CONTENT_TYPE_ORDINAL: value = MimeTypes.CACHE.lookup(value); _charset = MimeTypes.getCharsetFromContentType(value); break; case HttpHeaders.CONNECTION_ORDINAL: // looks rather clumsy, but the idea is to optimize for a single valued header switch (HttpHeaderValues.CACHE.getOrdinal(value)) { case -1: { String[] values = value.toString().split(","); for (int i = 0; values != null && i < values.length; i++) { CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim()); if (cb != null) { switch (cb.getOrdinal()) { case HttpHeaderValues.CLOSE_ORDINAL: _responseFields.add( HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER); _generator.setPersistent(false); break; case HttpHeaderValues.KEEP_ALIVE_ORDINAL: if (_version == HttpVersions.HTTP_1_0_ORDINAL) _responseFields.add( HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.KEEP_ALIVE_BUFFER); break; } } } break; } case HttpHeaderValues.CLOSE_ORDINAL: _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER); _generator.setPersistent(false); break; case HttpHeaderValues.KEEP_ALIVE_ORDINAL: if (_version == HttpVersions.HTTP_1_0_ORDINAL) _responseFields.put( HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.KEEP_ALIVE_BUFFER); break; } } _requestFields.add(name, value); }
/* ------------------------------------------------------------ */ public void putTo(Buffer buffer) throws IOException { int o = (_name instanceof CachedBuffer) ? ((CachedBuffer) _name).getOrdinal() : -1; if (o >= 0) buffer.put(_name); else { int s = _name.getIndex(); int e = _name.putIndex(); while (s < e) { byte b = _name.peek(s++); switch (b) { case '\r': case '\n': case ':': continue; default: buffer.put(b); } } } buffer.put((byte) ':'); buffer.put((byte) ' '); o = (_value instanceof CachedBuffer) ? ((CachedBuffer) _value).getOrdinal() : -1; if (o >= 0) buffer.put(_value); else { int s = _value.getIndex(); int e = _value.putIndex(); while (s < e) { byte b = _value.peek(s++); switch (b) { case '\r': case '\n': continue; default: buffer.put(b); } } } BufferUtil.putCRLF(buffer); }
/* ------------------------------------------------------------ */ public void sendContent(Object content) throws IOException { Resource resource = null; if (isClosed()) throw new IOException("Closed"); if (super._generator.isWritten()) throw new IllegalStateException("!empty"); // Convert HTTP content to contentl if (content instanceof HttpContent) { HttpContent httpContent = (HttpContent) content; Buffer contentType = httpContent.getContentType(); if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER)) { String enc = _response.getSetCharacterEncoding(); if (enc == null) _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType); else { if (contentType instanceof CachedBuffer) { CachedBuffer content_type = ((CachedBuffer) contentType).getAssociate(enc); if (content_type != null) _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type); else { _responseFields.put( HttpHeaders.CONTENT_TYPE_BUFFER, contentType + ";charset=" + QuotedStringTokenizer.quoteIfNeeded(enc, ";= ")); } } else { _responseFields.put( HttpHeaders.CONTENT_TYPE_BUFFER, contentType + ";charset=" + QuotedStringTokenizer.quoteIfNeeded(enc, ";= ")); } } } if (httpContent.getContentLength() > 0) _responseFields.putLongField( HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength()); Buffer lm = httpContent.getLastModified(); long lml = httpContent.getResource().lastModified(); if (lm != null) _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm); else if (httpContent.getResource() != null) { if (lml != -1) _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml); } boolean direct = _connector instanceof NIOConnector && ((NIOConnector) _connector).getUseDirectBuffers() && !(_connector instanceof SslConnector); content = direct ? httpContent.getDirectBuffer() : httpContent.getIndirectBuffer(); if (content == null) content = httpContent.getInputStream(); } else if (content instanceof Resource) { resource = (Resource) content; _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified()); content = resource.getInputStream(); } // Process content. if (content instanceof Buffer) { super._generator.addContent((Buffer) content, Generator.LAST); commitResponse(Generator.LAST); } else if (content instanceof InputStream) { InputStream in = (InputStream) content; try { int max = super._generator.prepareUncheckedAddContent(); Buffer buffer = super._generator.getUncheckedBuffer(); int len = buffer.readFrom(in, max); while (len >= 0) { super._generator.completeUncheckedAddContent(); _out.flush(); max = super._generator.prepareUncheckedAddContent(); buffer = super._generator.getUncheckedBuffer(); len = buffer.readFrom(in, max); } super._generator.completeUncheckedAddContent(); _out.flush(); } finally { if (resource != null) resource.release(); else in.close(); } } else throw new IllegalArgumentException("unknown content type?"); }
private synchronized void bufferPut(byte[] data) throws IOException { if (_maskGen != null) for (int i = 0; i < data.length; i++) data[i] ^= _mask[+_m++ % 4]; _buffer.put(data); }