1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.client.io;
20
21 import java.nio.ByteBuffer;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.eclipse.jetty.util.StringUtil;
26 import org.eclipse.jetty.util.Utf8LineParser;
27 import org.eclipse.jetty.websocket.api.UpgradeException;
28 import org.eclipse.jetty.websocket.client.ClientUpgradeResponse;
29
30
31
32
33 public class HttpResponseHeaderParser
34 {
35 private enum State
36 {
37 STATUS_LINE,
38 HEADER,
39 END
40 }
41
42 private static final Pattern PAT_HEADER = Pattern.compile("([^:]+):\\s*(.*)");
43 private static final Pattern PAT_STATUS_LINE = Pattern.compile("^HTTP/1.[01]\\s+(\\d+)\\s+(.*)",Pattern.CASE_INSENSITIVE);
44
45 private ClientUpgradeResponse response;
46 private Utf8LineParser lineParser;
47 private State state;
48
49 public HttpResponseHeaderParser()
50 {
51 this.lineParser = new Utf8LineParser();
52 this.state = State.STATUS_LINE;
53 }
54
55 public boolean isDone()
56 {
57 return (state == State.END);
58 }
59
60 public ClientUpgradeResponse parse(ByteBuffer buf) throws UpgradeException
61 {
62 while (!isDone() && (buf.remaining() > 0))
63 {
64 String line = lineParser.parse(buf);
65 if (line != null)
66 {
67 if (parseHeader(line))
68 {
69 return this.response;
70 }
71 }
72 }
73 return null;
74 }
75
76 private boolean parseHeader(String line)
77 {
78 switch (state)
79 {
80 case STATUS_LINE:
81 {
82 this.response = new ClientUpgradeResponse();
83 Matcher mat = PAT_STATUS_LINE.matcher(line);
84 if (!mat.matches())
85 {
86 throw new UpgradeException("Unexpected HTTP upgrade response status line [" + line + "]");
87 }
88
89 try
90 {
91 response.setStatusCode(Integer.parseInt(mat.group(1)));
92 }
93 catch (NumberFormatException e)
94 {
95 throw new UpgradeException("Unexpected HTTP upgrade response status code",e);
96 }
97 response.setStatusReason(mat.group(2));
98 state = State.HEADER;
99 break;
100 }
101 case HEADER:
102 {
103 if (StringUtil.isBlank(line))
104 {
105 state = State.END;
106 return parseHeader(line);
107 }
108
109 Matcher header = PAT_HEADER.matcher(line);
110 if (header.matches())
111 {
112 String headerName = header.group(1);
113 String headerValue = header.group(2);
114
115 response.addHeader(headerName,headerValue);
116 }
117 break;
118 }
119 case END:
120 state = State.STATUS_LINE;
121 return true;
122 }
123 return false;
124 }
125 }