1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.beep4j.internal;
17
18 import java.nio.ByteBuffer;
19 import java.nio.CharBuffer;
20 import java.nio.charset.Charset;
21
22 import net.sf.beep4j.ProtocolException;
23
24
25
26
27
28
29
30
31 final class HeaderState implements ParseState {
32
33 private static final int NOT_FOUND = -1;
34
35 private static final byte CR = '\r';
36
37 private static final byte LF = '\n';
38
39 private static final int MAX_HEADER_LENGTH = 61;
40
41 private final ByteBuffer tmp = ByteBuffer.allocate(MAX_HEADER_LENGTH);
42
43 public boolean process(ByteBuffer buffer, ParseStateContext context) {
44 int position = buffer.position();
45 int index = findLF(buffer);
46
47 if (index != NOT_FOUND) {
48 checkHeaderLength(tmp.position() + index - 1);
49
50 int limit = buffer.limit();
51 buffer.limit(index + position);
52 tmp.put(buffer);
53 buffer.limit(limit);
54 tmp.flip();
55
56
57 tmp.position(tmp.limit() - 1);
58 if (tmp.get() != CR) {
59 throw new ProtocolException("found LF but missing CR in header");
60 }
61 tmp.rewind();
62
63
64 tmp.limit(tmp.limit() - 1);
65
66
67 buffer.position(buffer.position() + 1);
68
69 String[] tokens = tokenize(tmp);
70 context.handleHeader(tokens);
71
72 tmp.clear();
73
74 return buffer.hasRemaining();
75
76 } else {
77 checkHeaderLength(tmp.position() + buffer.remaining() - 1);
78 tmp.put(buffer);
79 return false;
80 }
81 }
82
83 private void checkHeaderLength(int length) {
84 if (length > MAX_HEADER_LENGTH) {
85 throw new ProtocolException("header longer than maximum: "
86 + length + " > " + MAX_HEADER_LENGTH);
87 }
88 }
89
90 private String[] tokenize(ByteBuffer header) {
91 boolean space = false;
92
93 ByteBuffer copy = header.asReadOnlyBuffer();
94 int remaining = copy.remaining();
95 for (int i = 0; i < remaining; i++) {
96 byte current = copy.get();
97 if (space && current == (byte) ' ') {
98 throw new ProtocolException("two consecutive spaces in header");
99 }
100 space = current == (byte) ' ';
101 }
102
103 Charset charset = Charset.forName("US-ASCII");
104 CharBuffer buffer = charset.decode(header);
105
106 String[] tmp = buffer.toString().split(" ");
107 return tmp;
108 }
109
110 private int findLF(ByteBuffer buf) {
111 if (buf.hasRemaining()) {
112 buf.mark();
113 int remaining = buf.remaining();
114
115 for (int i = 0; i < remaining; i++) {
116 if (buf.get() == LF) {
117 buf.reset();
118 return i;
119 }
120 }
121
122 buf.reset();
123 }
124
125 return NOT_FOUND;
126 }
127
128 }