jruby-http-kit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +1 -0
- data/example/config.ru +9 -0
- data/example/hello_world.rb +17 -0
- data/example/rack.rb +11 -0
- data/example/ring.rb +31 -0
- data/example/sinatra/app.rb +9 -0
- data/example/sinatra/config.ru +8 -0
- data/example/webmachine/Gemfile +4 -0
- data/example/webmachine/Gemfile.lock +16 -0
- data/example/webmachine/app.rb +37 -0
- data/jruby-http-kit.gemspec +25 -0
- data/lib/http_kit/rack_handler.rb +139 -0
- data/lib/http_kit/server.rb +62 -0
- data/lib/http_kit/version.rb +3 -0
- data/lib/http_kit.rb +6 -0
- data/lib/java/clojure-1.5.1.jar +0 -0
- data/lib/java/http-kit.jar +0 -0
- data/lib/rack/handler/http_kit.rb +3 -0
- data/lib/rack/http_kit.rb +3 -0
- data/lib/webmachine/adapters/ring.rb +135 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/test_resource.rb +75 -0
- data/spec/webmachine/ring_adapter_spec.rb +127 -0
- data/src/.classpath +7 -0
- data/src/.project +17 -0
- data/src/org/httpkit/BytesInputStream.class +0 -0
- data/src/org/httpkit/BytesInputStream.java +83 -0
- data/src/org/httpkit/DateFormatter.class +0 -0
- data/src/org/httpkit/DynamicBytes.class +0 -0
- data/src/org/httpkit/DynamicBytes.java +76 -0
- data/src/org/httpkit/HTTPException.class +0 -0
- data/src/org/httpkit/HTTPException.java +10 -0
- data/src/org/httpkit/HeaderMap.class +0 -0
- data/src/org/httpkit/HeaderMap.java +98 -0
- data/src/org/httpkit/HttpMethod.class +0 -0
- data/src/org/httpkit/HttpMethod.java +28 -0
- data/src/org/httpkit/HttpStatus.class +0 -0
- data/src/org/httpkit/HttpStatus.java +416 -0
- data/src/org/httpkit/HttpUtils.class +0 -0
- data/src/org/httpkit/HttpUtils.java +484 -0
- data/src/org/httpkit/HttpVersion.class +0 -0
- data/src/org/httpkit/HttpVersion.java +5 -0
- data/src/org/httpkit/LineReader.class +0 -0
- data/src/org/httpkit/LineReader.java +52 -0
- data/src/org/httpkit/LineTooLargeException.class +0 -0
- data/src/org/httpkit/LineTooLargeException.java +13 -0
- data/src/org/httpkit/PrefixThreadFactory.class +0 -0
- data/src/org/httpkit/PrefixThreadFactory.java +20 -0
- data/src/org/httpkit/PriorityQueue.class +0 -0
- data/src/org/httpkit/PriorityQueue.java +235 -0
- data/src/org/httpkit/ProtocolException.class +0 -0
- data/src/org/httpkit/ProtocolException.java +10 -0
- data/src/org/httpkit/RequestTooLargeException.class +0 -0
- data/src/org/httpkit/RequestTooLargeException.java +10 -0
- data/src/org/httpkit/client/AbortException.class +0 -0
- data/src/org/httpkit/client/AbortException.java +13 -0
- data/src/org/httpkit/client/Decoder.class +0 -0
- data/src/org/httpkit/client/Decoder.java +182 -0
- data/src/org/httpkit/client/Handler.class +0 -0
- data/src/org/httpkit/client/HttpClient.class +0 -0
- data/src/org/httpkit/client/HttpClient.java +393 -0
- data/src/org/httpkit/client/HttpsRequest.class +0 -0
- data/src/org/httpkit/client/HttpsRequest.java +141 -0
- data/src/org/httpkit/client/IFilter$1.class +0 -0
- data/src/org/httpkit/client/IFilter$MaxBodyFilter.class +0 -0
- data/src/org/httpkit/client/IFilter.class +0 -0
- data/src/org/httpkit/client/IFilter.java +53 -0
- data/src/org/httpkit/client/IRespListener.class +0 -0
- data/src/org/httpkit/client/IRespListener.java +30 -0
- data/src/org/httpkit/client/IResponseHandler.class +0 -0
- data/src/org/httpkit/client/IResponseHandler.java +18 -0
- data/src/org/httpkit/client/PersistentConn.class +0 -0
- data/src/org/httpkit/client/PersistentConn.java +33 -0
- data/src/org/httpkit/client/Request.class +0 -0
- data/src/org/httpkit/client/Request.java +74 -0
- data/src/org/httpkit/client/RequestConfig.class +0 -0
- data/src/org/httpkit/client/RequestConfig.java +28 -0
- data/src/org/httpkit/client/RespListener.class +0 -0
- data/src/org/httpkit/client/RespListener.java +160 -0
- data/src/org/httpkit/client/SslContextFactory.class +0 -0
- data/src/org/httpkit/client/SslContextFactory.java +79 -0
- data/src/org/httpkit/client/State.class +0 -0
- data/src/org/httpkit/client/TimeoutException.class +0 -0
- data/src/org/httpkit/client/TimeoutException.java +12 -0
- data/src/org/httpkit/client/TrustManagerFactory$1.class +0 -0
- data/src/org/httpkit/client/TrustManagerFactory.class +0 -0
- data/src/org/httpkit/server/AsyncChannel.class +0 -0
- data/src/org/httpkit/server/AsyncChannel.java +286 -0
- data/src/org/httpkit/server/ClojureRing.class +0 -0
- data/src/org/httpkit/server/Frame$BinaryFrame.class +0 -0
- data/src/org/httpkit/server/Frame$CloseFrame.class +0 -0
- data/src/org/httpkit/server/Frame$PingFrame.class +0 -0
- data/src/org/httpkit/server/Frame$TextFrame.class +0 -0
- data/src/org/httpkit/server/Frame.class +0 -0
- data/src/org/httpkit/server/Frame.java +73 -0
- data/src/org/httpkit/server/HttpAtta.class +0 -0
- data/src/org/httpkit/server/HttpAtta.java +10 -0
- data/src/org/httpkit/server/HttpDecoder$State.class +0 -0
- data/src/org/httpkit/server/HttpDecoder.class +0 -0
- data/src/org/httpkit/server/HttpDecoder.java +202 -0
- data/src/org/httpkit/server/HttpHandler.class +0 -0
- data/src/org/httpkit/server/HttpRequest.class +0 -0
- data/src/org/httpkit/server/HttpRequest.java +109 -0
- data/src/org/httpkit/server/HttpServer.class +0 -0
- data/src/org/httpkit/server/HttpServer.java +281 -0
- data/src/org/httpkit/server/IHandler.class +0 -0
- data/src/org/httpkit/server/IHandler.java +12 -0
- data/src/org/httpkit/server/LinkingRunnable.class +0 -0
- data/src/org/httpkit/server/Rack.class +0 -0
- data/src/org/httpkit/server/RackApplication.class +0 -0
- data/src/org/httpkit/server/RackApplication.java +10 -0
- data/src/org/httpkit/server/RackHandler$1.class +0 -0
- data/src/org/httpkit/server/RackHandler.class +0 -0
- data/src/org/httpkit/server/RackHandler.java +259 -0
- data/src/org/httpkit/server/RackHttpHandler.class +0 -0
- data/src/org/httpkit/server/RackHttpHandler.java +20 -0
- data/src/org/httpkit/server/RespCallback.class +0 -0
- data/src/org/httpkit/server/RespCallback.java +19 -0
- data/src/org/httpkit/server/RingHandler$1.class +0 -0
- data/src/org/httpkit/server/RingHandler.class +0 -0
- data/src/org/httpkit/server/RingHandler.java +222 -0
- data/src/org/httpkit/server/ServerAtta.class +0 -0
- data/src/org/httpkit/server/ServerAtta.java +22 -0
- data/src/org/httpkit/server/WSDecoder$State.class +0 -0
- data/src/org/httpkit/server/WSDecoder.class +0 -0
- data/src/org/httpkit/server/WSDecoder.java +181 -0
- data/src/org/httpkit/server/WSHandler.class +0 -0
- data/src/org/httpkit/server/WsAtta.class +0 -0
- data/src/org/httpkit/server/WsAtta.java +11 -0
- data/src/org/httpkit/timer/CancelableFutureTask.class +0 -0
- data/src/org/httpkit/timer/CancelableFutureTask.java +52 -0
- data/src/org/httpkit/timer/TimerService.class +0 -0
- data/src/org/httpkit/timer/TimerService.java +89 -0
- metadata +241 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
package org.httpkit;
|
|
2
|
+
|
|
3
|
+
import java.util.Arrays;
|
|
4
|
+
import java.util.Queue;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Copy and modified from java.util.PriorityQueue. Remove unused method. Modify
|
|
8
|
+
* {@code remove} to return the removed element
|
|
9
|
+
* <p/>
|
|
10
|
+
* used by timer and the client
|
|
11
|
+
*
|
|
12
|
+
* @param <E>
|
|
13
|
+
*/
|
|
14
|
+
@SuppressWarnings("unchecked")
|
|
15
|
+
public class PriorityQueue<E> {
|
|
16
|
+
|
|
17
|
+
private static final int DEFAULT_INITIAL_CAPACITY = 11;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Priority queue represented as a balanced binary heap: the two children of
|
|
21
|
+
* queue[n] are queue[2*n+1] and queue[2*(n+1)]. The priority queue is
|
|
22
|
+
* ordered by comparator, or by the elements' natural ordering, if
|
|
23
|
+
* comparator is null: For each node n in the heap and each descendant d of
|
|
24
|
+
* n, n <= d. The element with the lowest value is in queue[0], assuming the
|
|
25
|
+
* queue is nonempty.
|
|
26
|
+
*/
|
|
27
|
+
private transient Object[] queue;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The number of elements in the priority queue.
|
|
31
|
+
*/
|
|
32
|
+
private int size = 0;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates a {@code PriorityQueue} with the specified initial capacity that
|
|
36
|
+
* orders its elements according to their {@linkplain Comparable natural
|
|
37
|
+
* ordering}.
|
|
38
|
+
* <p/>
|
|
39
|
+
* the initial capacity for this priority queue
|
|
40
|
+
*
|
|
41
|
+
* @throws IllegalArgumentException if {@code initialCapacity} is less than 1
|
|
42
|
+
*/
|
|
43
|
+
public PriorityQueue() {
|
|
44
|
+
this.queue = new Object[DEFAULT_INITIAL_CAPACITY];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The maximum size of array to allocate. Some VMs reserve some header words
|
|
49
|
+
* in an array. Attempts to allocate larger arrays may result in
|
|
50
|
+
* OutOfMemoryError: Requested array size exceeds VM limit
|
|
51
|
+
*/
|
|
52
|
+
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Increases the capacity of the array.
|
|
56
|
+
*
|
|
57
|
+
* @param minCapacity the desired minimum capacity
|
|
58
|
+
*/
|
|
59
|
+
private void grow(int minCapacity) {
|
|
60
|
+
int oldCapacity = queue.length;
|
|
61
|
+
// Double size if small; else grow by 50%
|
|
62
|
+
int newCapacity = oldCapacity
|
|
63
|
+
+ ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
|
|
64
|
+
// overflow-conscious code
|
|
65
|
+
if (newCapacity - MAX_ARRAY_SIZE > 0)
|
|
66
|
+
newCapacity = hugeCapacity(minCapacity);
|
|
67
|
+
queue = Arrays.copyOf(queue, newCapacity);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static int hugeCapacity(int minCapacity) {
|
|
71
|
+
if (minCapacity < 0) // overflow
|
|
72
|
+
throw new OutOfMemoryError();
|
|
73
|
+
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Inserts the specified element into this priority queue.
|
|
78
|
+
*
|
|
79
|
+
* @return {@code true} (as specified by {@link Queue#offer})
|
|
80
|
+
* @throws ClassCastException if the specified element cannot be compared with elements
|
|
81
|
+
* currently in this priority queue according to the priority
|
|
82
|
+
* queue's ordering
|
|
83
|
+
* @throws NullPointerException if the specified element is null
|
|
84
|
+
*/
|
|
85
|
+
public boolean offer(E e) {
|
|
86
|
+
if (e == null)
|
|
87
|
+
throw new NullPointerException();
|
|
88
|
+
int i = size;
|
|
89
|
+
if (i >= queue.length)
|
|
90
|
+
grow(i + 1);
|
|
91
|
+
size = i + 1;
|
|
92
|
+
if (i == 0)
|
|
93
|
+
queue[0] = e;
|
|
94
|
+
else
|
|
95
|
+
siftUp(i, e);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Retrieves, but does not remove, the head of this queue, or returns null
|
|
101
|
+
* if this queue is empty.
|
|
102
|
+
*
|
|
103
|
+
* @return
|
|
104
|
+
*/
|
|
105
|
+
public E peek() {
|
|
106
|
+
if (size == 0)
|
|
107
|
+
return null;
|
|
108
|
+
return (E) queue[0];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Removes a single instance of the specified element from this queue, if it
|
|
113
|
+
* is present. More formally, removes an element {@code e} such that
|
|
114
|
+
* {@code o.equals(e)}, if this queue contains one or more such elements.
|
|
115
|
+
* Returns {@code true} if and only if this queue contained the specified
|
|
116
|
+
* element (or equivalently, if this queue changed as a result of the call).
|
|
117
|
+
*
|
|
118
|
+
* @param o element to be removed from this queue, if present
|
|
119
|
+
* @return Element removed
|
|
120
|
+
*/
|
|
121
|
+
public E remove(Object o) {
|
|
122
|
+
for (int i = 0; i < size; i++) {
|
|
123
|
+
if (queue[i].equals(o)) {
|
|
124
|
+
E e = (E) queue[i];
|
|
125
|
+
removeAt(i);
|
|
126
|
+
return e;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public int size() {
|
|
133
|
+
return size;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Retrieves and removes the head of this queue, or returns null if this
|
|
138
|
+
* queue is empty.
|
|
139
|
+
*/
|
|
140
|
+
public E poll() {
|
|
141
|
+
if (size == 0)
|
|
142
|
+
return null;
|
|
143
|
+
int s = --size;
|
|
144
|
+
E result = (E) queue[0];
|
|
145
|
+
E x = (E) queue[s];
|
|
146
|
+
queue[s] = null;
|
|
147
|
+
if (s != 0)
|
|
148
|
+
siftDown(0, x);
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Removes the ith element from queue.
|
|
154
|
+
* <p/>
|
|
155
|
+
* Normally this method leaves the elements at up to i-1, inclusive,
|
|
156
|
+
* untouched. Under these circumstances, it returns null. Occasionally, in
|
|
157
|
+
* order to maintain the heap invariant, it must swap a later element of the
|
|
158
|
+
* list with one earlier than i. Under these circumstances, this method
|
|
159
|
+
* returns the element that was previously at the end of the list and is now
|
|
160
|
+
* at some position before i. This fact is used by iterator.remove so as to
|
|
161
|
+
* avoid missing traversing elements.
|
|
162
|
+
*/
|
|
163
|
+
private E removeAt(int i) {
|
|
164
|
+
assert i >= 0 && i < size;
|
|
165
|
+
int s = --size;
|
|
166
|
+
if (s == i) // removed last element
|
|
167
|
+
queue[i] = null;
|
|
168
|
+
else {
|
|
169
|
+
E moved = (E) queue[s];
|
|
170
|
+
queue[s] = null;
|
|
171
|
+
siftDown(i, moved);
|
|
172
|
+
if (queue[i] == moved) {
|
|
173
|
+
siftUp(i, moved);
|
|
174
|
+
if (queue[i] != moved)
|
|
175
|
+
return moved;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Inserts item x at position k, maintaining heap invariant by promoting x
|
|
183
|
+
* up the tree until it is greater than or equal to its parent, or is the
|
|
184
|
+
* root.
|
|
185
|
+
* <p/>
|
|
186
|
+
* To simplify and speed up coercions and comparisons. the Comparable and
|
|
187
|
+
* Comparator versions are separated into different methods that are
|
|
188
|
+
* otherwise identical. (Similarly for siftDown.)
|
|
189
|
+
*
|
|
190
|
+
* @param k the position to fill
|
|
191
|
+
* @param x the item to insert
|
|
192
|
+
*/
|
|
193
|
+
private void siftUp(int k, E x) {
|
|
194
|
+
Comparable<? super E> key = (Comparable<? super E>) x;
|
|
195
|
+
while (k > 0) {
|
|
196
|
+
int parent = (k - 1) >>> 1;
|
|
197
|
+
Object e = queue[parent];
|
|
198
|
+
if (key.compareTo((E) e) >= 0)
|
|
199
|
+
break;
|
|
200
|
+
queue[k] = e;
|
|
201
|
+
k = parent;
|
|
202
|
+
}
|
|
203
|
+
queue[k] = key;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Inserts item x at position k, maintaining heap invariant by demoting x
|
|
208
|
+
* down the tree repeatedly until it is less than or equal to its children
|
|
209
|
+
* or is a leaf.
|
|
210
|
+
*
|
|
211
|
+
* @param k the position to fill
|
|
212
|
+
* @param x the item to insert
|
|
213
|
+
*/
|
|
214
|
+
private void siftDown(int k, E x) {
|
|
215
|
+
Comparable<? super E> key = (Comparable<? super E>) x;
|
|
216
|
+
int half = size >>> 1; // loop while a non-leaf
|
|
217
|
+
while (k < half) {
|
|
218
|
+
int child = (k << 1) + 1; // assume left child is least
|
|
219
|
+
Object c = queue[child];
|
|
220
|
+
int right = child + 1;
|
|
221
|
+
if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
|
|
222
|
+
c = queue[child = right];
|
|
223
|
+
if (key.compareTo((E) c) <= 0)
|
|
224
|
+
break;
|
|
225
|
+
queue[k] = c;
|
|
226
|
+
k = child;
|
|
227
|
+
}
|
|
228
|
+
queue[k] = key;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@Override
|
|
232
|
+
public String toString() {
|
|
233
|
+
return "size=" + size;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
package org.httpkit.client;
|
|
2
|
+
|
|
3
|
+
import org.httpkit.*;
|
|
4
|
+
|
|
5
|
+
import java.nio.ByteBuffer;
|
|
6
|
+
import java.util.Map;
|
|
7
|
+
import java.util.TreeMap;
|
|
8
|
+
|
|
9
|
+
import static org.httpkit.HttpUtils.*;
|
|
10
|
+
import static org.httpkit.HttpVersion.HTTP_1_0;
|
|
11
|
+
import static org.httpkit.HttpVersion.HTTP_1_1;
|
|
12
|
+
import static org.httpkit.client.State.*;
|
|
13
|
+
|
|
14
|
+
enum State {
|
|
15
|
+
ALL_READ, READ_CHUNK_DELIMITER, READ_CHUNK_FOOTER, READ_CHUNK_SIZE,
|
|
16
|
+
READ_CHUNKED_CONTENT, READ_FIXED_LENGTH_CONTENT, READ_HEADER, READ_INITIAL,
|
|
17
|
+
READ_VARIABLE_LENGTH_CONTENT
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public class Decoder {
|
|
21
|
+
|
|
22
|
+
private final Map<String, Object> headers = new TreeMap<String, Object>();
|
|
23
|
+
// package visible
|
|
24
|
+
final IRespListener listener;
|
|
25
|
+
private final LineReader lineReader;
|
|
26
|
+
int readRemaining = 0;
|
|
27
|
+
State state = READ_INITIAL;
|
|
28
|
+
private final HttpMethod method;
|
|
29
|
+
|
|
30
|
+
private boolean emptyBodyExpected = false;
|
|
31
|
+
|
|
32
|
+
public Decoder(IRespListener listener, HttpMethod method) {
|
|
33
|
+
this.listener = listener;
|
|
34
|
+
this.method = method;
|
|
35
|
+
lineReader = new LineReader(8096);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private void parseInitialLine(String sb) throws ProtocolException, AbortException {
|
|
39
|
+
int aStart;
|
|
40
|
+
int aEnd;
|
|
41
|
+
int bStart;
|
|
42
|
+
int bEnd;
|
|
43
|
+
int cStart;
|
|
44
|
+
int cEnd;
|
|
45
|
+
|
|
46
|
+
aStart = findNonWhitespace(sb, 0);
|
|
47
|
+
aEnd = findWhitespace(sb, aStart);
|
|
48
|
+
|
|
49
|
+
bStart = findNonWhitespace(sb, aEnd);
|
|
50
|
+
bEnd = findWhitespace(sb, bStart);
|
|
51
|
+
|
|
52
|
+
cStart = findNonWhitespace(sb, bEnd);
|
|
53
|
+
cEnd = findEndOfString(sb);
|
|
54
|
+
|
|
55
|
+
if ((cStart < cEnd)
|
|
56
|
+
// Account for buggy web servers that omit Reason-Phrase from Status-Line.
|
|
57
|
+
// http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#Response
|
|
58
|
+
|| (cStart == cEnd && bStart < bEnd)) {
|
|
59
|
+
try {
|
|
60
|
+
int status = Integer.parseInt(sb.substring(bStart, bEnd));
|
|
61
|
+
// status is not 1xx, 204 or 304, then the body is unbounded.
|
|
62
|
+
// RFC2616, section 4.4
|
|
63
|
+
emptyBodyExpected = status / 100 == 1 || status == 204 || status == 304;
|
|
64
|
+
HttpStatus s = HttpStatus.valueOf(status);
|
|
65
|
+
|
|
66
|
+
HttpVersion version = HTTP_1_1;
|
|
67
|
+
if ("HTTP/1.0".equals(sb.substring(aStart, aEnd))) {
|
|
68
|
+
version = HTTP_1_0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
listener.onInitialLineReceived(version, s);
|
|
72
|
+
state = READ_HEADER;
|
|
73
|
+
} catch (NumberFormatException e) {
|
|
74
|
+
throw new ProtocolException("not http protocol? " + sb);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
throw new ProtocolException("not http protocol? " + sb);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public State decode(ByteBuffer buffer) throws LineTooLargeException, ProtocolException,
|
|
82
|
+
AbortException {
|
|
83
|
+
String line;
|
|
84
|
+
while (buffer.hasRemaining() && state != State.ALL_READ) {
|
|
85
|
+
switch (state) {
|
|
86
|
+
case READ_INITIAL:
|
|
87
|
+
if ((line = lineReader.readLine(buffer)) != null) {
|
|
88
|
+
parseInitialLine(line);
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case READ_HEADER:
|
|
92
|
+
readHeaders(buffer);
|
|
93
|
+
break;
|
|
94
|
+
case READ_CHUNK_SIZE:
|
|
95
|
+
line = lineReader.readLine(buffer);
|
|
96
|
+
if (line != null && !line.isEmpty()) {
|
|
97
|
+
readRemaining = getChunkSize(line);
|
|
98
|
+
if (readRemaining == 0) {
|
|
99
|
+
state = READ_CHUNK_FOOTER;
|
|
100
|
+
} else {
|
|
101
|
+
state = READ_CHUNKED_CONTENT;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case READ_FIXED_LENGTH_CONTENT:
|
|
106
|
+
readBody(buffer, ALL_READ);
|
|
107
|
+
break;
|
|
108
|
+
case READ_CHUNKED_CONTENT:
|
|
109
|
+
readBody(buffer, READ_CHUNK_DELIMITER);
|
|
110
|
+
break;
|
|
111
|
+
case READ_CHUNK_FOOTER:
|
|
112
|
+
readEmptyLine(buffer);
|
|
113
|
+
state = ALL_READ;
|
|
114
|
+
break;
|
|
115
|
+
case READ_CHUNK_DELIMITER:
|
|
116
|
+
readEmptyLine(buffer);
|
|
117
|
+
state = READ_CHUNK_SIZE;
|
|
118
|
+
break;
|
|
119
|
+
case READ_VARIABLE_LENGTH_CONTENT:
|
|
120
|
+
readBody(buffer, null);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return state;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private void readBody(ByteBuffer buffer, State nextState) throws AbortException {
|
|
128
|
+
int toRead = Math.min(buffer.remaining(), readRemaining);
|
|
129
|
+
byte[] bytes = new byte[toRead];
|
|
130
|
+
buffer.get(bytes, 0, toRead);
|
|
131
|
+
listener.onBodyReceived(bytes, toRead);
|
|
132
|
+
if (nextState != null) {
|
|
133
|
+
readRemaining -= toRead;
|
|
134
|
+
if (readRemaining == 0) {
|
|
135
|
+
state = nextState;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void readEmptyLine(ByteBuffer buffer) {
|
|
141
|
+
byte b = buffer.get();
|
|
142
|
+
if (b == CR && buffer.hasRemaining()) {
|
|
143
|
+
buffer.get(); // should be LF
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private void readHeaders(ByteBuffer buffer) throws LineTooLargeException, AbortException {
|
|
148
|
+
String line = lineReader.readLine(buffer);
|
|
149
|
+
while (line != null && !line.isEmpty()) {
|
|
150
|
+
HttpUtils.splitAndAddHeader(line, headers);
|
|
151
|
+
line = lineReader.readLine(buffer);
|
|
152
|
+
}
|
|
153
|
+
if (line == null)
|
|
154
|
+
return; // data is not received enough. for next run
|
|
155
|
+
listener.onHeadersReceived(headers);
|
|
156
|
+
if (method == HttpMethod.HEAD) {
|
|
157
|
+
state = ALL_READ;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
String te = HttpUtils.getStringValue(headers, TRANSFER_ENCODING);
|
|
162
|
+
if (CHUNKED.equals(te)) {
|
|
163
|
+
state = READ_CHUNK_SIZE;
|
|
164
|
+
} else {
|
|
165
|
+
String cl = HttpUtils.getStringValue(headers, CONTENT_LENGTH);
|
|
166
|
+
if (cl != null) {
|
|
167
|
+
readRemaining = Integer.parseInt(cl);
|
|
168
|
+
if (readRemaining == 0) {
|
|
169
|
+
state = ALL_READ;
|
|
170
|
+
} else {
|
|
171
|
+
state = READ_FIXED_LENGTH_CONTENT;
|
|
172
|
+
}
|
|
173
|
+
} else if (emptyBodyExpected) {
|
|
174
|
+
state = ALL_READ;
|
|
175
|
+
} else {
|
|
176
|
+
state = READ_VARIABLE_LENGTH_CONTENT;
|
|
177
|
+
// for readBody min
|
|
178
|
+
readRemaining = Integer.MAX_VALUE;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
Binary file
|
|
Binary file
|