xitiomet / placebohttp (http://openstatic.org/)
Embeded Http server for gcj/java applications. PlaceboHttp uses an automatic session management system, Treating each session as a HttpRequest queue.
| commit 19: | 81f8f47a533a |
| parent 18: | 00cf4ae79f6b |
| branch: | default |
Changed (Δ3.3 KB):
Makefile (4 lines added, 1 lines removed)
src/PlaceboBase.java (9 lines added, 1 lines removed)
src/org/openstatic/http/PlaceboHttpServer.java (19 lines added, 1 lines removed)
src/org/openstatic/placebo/ControlPanel.java (42 lines added, 6 lines removed)
src/org/openstatic/placebo/CoreServer.java (152 lines added, 105 lines removed)
| … | … | @@ -51,10 +51,13 @@ build/org/openstatic/placebo/ControlPane |
51 |
51 |
build/org/openstatic/placebo/CoreServer.class: src/org/openstatic/placebo/CoreServer.java |
52 |
52 |
$(JC) $(JC_FLAGS) --classpath=$(CLASS_PATH) -C $< |
53 |
53 |
|
54 |
build/org/openstatic/util/JTextAreaOutputStream.class: src/org/openstatic/util/JTextAreaOutputStream.java |
|
55 |
$(JC) $(JC_FLAGS) --classpath=$(CLASS_PATH) -C $< |
|
56 |
||
54 |
57 |
# Main Builds |
55 |
58 |
# ------------------------------------------------------------------------------- |
56 |
59 |
|
57 |
placebohttp.jar: build/org/openstatic/http/PlaceboHttpServer.class build/org/openstatic/http/PlaceboSession.class build/org/openstatic/http/HttpRequest.class build/org/openstatic/http/HttpRequestThread.class build/org/openstatic/http/HttpResponse.class build/PlaceboBase.class build/org/openstatic/placebo/ControlPanel.class build/org/openstatic/placebo/CoreServer.class |
|
60 |
placebohttp.jar: build/org/openstatic/http/PlaceboHttpServer.class build/org/openstatic/http/PlaceboSession.class build/org/openstatic/http/HttpRequest.class build/org/openstatic/http/HttpRequestThread.class build/org/openstatic/http/HttpResponse.class build/PlaceboBase.class build/org/openstatic/placebo/ControlPanel.class build/org/openstatic/placebo/CoreServer.class build/org/openstatic/util/JTextAreaOutputStream.class |
|
58 |
61 |
$(JAR) -cvmf manifest.mf $@ -C build org -C build PlaceboBase.class www |
59 |
62 |
|
60 |
63 |
clean: |
Up to file-list src/PlaceboBase.java:
| … | … | @@ -11,6 +11,7 @@ public class PlaceboBase |
11 |
11 |
System.err.println(" --root [path] Set webroot"); |
12 |
12 |
System.err.println(" --port [port] Specify HTTP listening port"); |
13 |
13 |
System.err.println(" --help display this menu"); |
14 |
System.err.println(" --swing Start up in swing control panel"); |
|
14 |
15 |
System.err.println(""); |
15 |
16 |
System.err.println(""); |
16 |
17 |
} |
| … | … | @@ -57,12 +58,19 @@ public class PlaceboBase |
57 |
58 |
if (arg.equals("--swing")) |
58 |
59 |
{ |
59 |
60 |
ControlPanel cp = new ControlPanel(); |
61 |
cp.setPort(http_port); |
|
62 |
cp.setWebRoot(web_root); |
|
63 |
cp.setDebug(debug); |
|
60 |
64 |
} |
61 |
65 |
} |
62 |
66 |
|
63 |
67 |
if (start_engine) |
64 |
68 |
{ |
65 |
CoreServer |
|
69 |
CoreServer x = new CoreServer(); |
|
70 |
x.setPort(http_port); |
|
71 |
x.setWebRoot(web_root); |
|
72 |
x.setDebug(debug); |
|
73 |
x.start(); |
|
66 |
74 |
} |
67 |
75 |
} |
68 |
76 |
Up to file-list src/org/openstatic/http/PlaceboHttpServer.java:
| … | … | @@ -20,6 +20,11 @@ public class PlaceboHttpServer extends T |
20 |
20 |
private ServerSocket ss; |
21 |
21 |
private int routing_mode; |
22 |
22 |
|
23 |
public PlaceboHttpServer() |
|
24 |
{ |
|
25 |
this(80); |
|
26 |
} |
|
27 |
||
23 |
28 |
public PlaceboHttpServer(int port) |
24 |
29 |
{ |
25 |
30 |
this.routing_mode = 0; |
| … | … | @@ -32,6 +37,12 @@ public class PlaceboHttpServer extends T |
32 |
37 |
this.keep_running = true; |
33 |
38 |
} |
34 |
39 |
|
40 |
public void setPort(int value) |
|
41 |
{ |
|
42 |
this.port = value; |
|
43 |
this.myName = "Placebo:" + String.valueOf(this.port); |
|
44 |
} |
|
45 |
||
35 |
46 |
public PlaceboSession getNextSession() |
36 |
47 |
{ |
37 |
48 |
this.routing_mode = 1; |
| … | … | @@ -39,7 +50,6 @@ public class PlaceboHttpServer extends T |
39 |
50 |
{ |
40 |
51 |
return session_queue.take(); |
41 |
52 |
} catch (Exception e) { |
42 |
//System.err.println(e.getMessage() + " / " + e.toString()); |
|
43 |
53 |
return null; |
44 |
54 |
} |
45 |
55 |
} |
| … | … | @@ -116,6 +126,7 @@ public class PlaceboHttpServer extends T |
116 |
126 |
logln(this.myName,"Init on port " + String.valueOf(this.port)); |
117 |
127 |
} catch (Exception n) {} |
118 |
128 |
logln(this.myName,"Entering Server Loop"); |
129 |
this.keep_running = true; |
|
119 |
130 |
while(this.keep_running) |
120 |
131 |
{ |
121 |
132 |
try |
| … | … | @@ -127,6 +138,7 @@ public class PlaceboHttpServer extends T |
127 |
138 |
} catch (Exception x) {} |
128 |
139 |
} |
129 |
140 |
} |
141 |
||
130 |
142 |
public void setDebug(boolean value) |
131 |
143 |
{ |
132 |
144 |
this.debug_mode = value; |
| … | … | @@ -179,6 +191,12 @@ public class PlaceboHttpServer extends T |
179 |
191 |
} |
180 |
192 |
} |
181 |
193 |
|
194 |
public void shutdown() |
|
195 |
{ |
|
196 |
this.keep_running = false; |
|
197 |
this.interrupt(); |
|
198 |
} |
|
199 |
||
182 |
200 |
private static String getPaddingSpace(int value) |
183 |
201 |
{ |
184 |
202 |
StringBuffer x = new StringBuffer(""); |
Up to file-list src/org/openstatic/placebo/ControlPanel.java:
1 |
1 |
package org.openstatic.placebo; |
2 |
2 |
|
3 |
3 |
import org.openstatic.placebo.CoreServer; |
4 |
import org.openstatic.util.JTextAreaOutputStream; |
|
4 |
5 |
import javax.swing.JFrame; |
5 |
6 |
import javax.swing.JLabel; |
6 |
7 |
import javax.swing.JPanel; |
| … | … | @@ -11,7 +12,6 @@ import javax.swing.JTextArea; |
11 |
12 |
import javax.swing.JScrollPane; |
12 |
13 |
import javax.swing.ScrollPaneConstants; |
13 |
14 |
import java.awt.GridLayout; |
14 |
import java.awt.FlowLayout; |
|
15 |
15 |
import java.awt.Toolkit; |
16 |
16 |
import java.awt.Dimension; |
17 |
17 |
import java.awt.event.ActionEvent; |
| … | … | @@ -22,6 +22,12 @@ public class ControlPanel extends JFrame |
22 |
22 |
{ |
23 |
23 |
private JButton start_btn; |
24 |
24 |
private JButton stop_btn; |
25 |
private JTextField port_field; |
|
26 |
private JTextField root_field; |
|
27 |
private JCheckBox debug_field; |
|
28 |
private JTextAreaOutputStream log_output; |
|
29 |
private JTextArea log_box; |
|
30 |
private CoreServer core; |
|
25 |
31 |
|
26 |
32 |
public void centerWindow() |
27 |
33 |
{ |
| … | … | @@ -32,7 +38,22 @@ public class ControlPanel extends JFrame |
32 |
38 |
this.setSize(420, 240); |
33 |
39 |
this.setLocation(WIDTH / 2 - 210, HEIGHT / 2 - 120); |
34 |
40 |
} |
35 |
||
41 |
||
42 |
public void setPort(int value) |
|
43 |
{ |
|
44 |
this.port_field.setText(String.valueOf(value)); |
|
45 |
} |
|
46 |
||
47 |
public void setDebug(boolean value) |
|
48 |
{ |
|
49 |
this.debug_field.setSelected(value); |
|
50 |
} |
|
51 |
||
52 |
public void setWebRoot(String value) |
|
53 |
{ |
|
54 |
this.root_field.setText(value); |
|
55 |
} |
|
56 |
||
36 |
57 |
public ControlPanel() |
37 |
58 |
{ |
38 |
59 |
super("Placebo Web Server"); |
| … | … | @@ -45,10 +66,15 @@ public class ControlPanel extends JFrame |
45 |
66 |
JPanel pane = new JPanel(new GridLayout(0,2,6,6)); |
46 |
67 |
pane.setSize(50,100); |
47 |
68 |
JLabel port_label = new JLabel("Port:", JLabel.TRAILING); |
48 |
|
|
69 |
port_field = new JTextField(15); |
|
70 |
port_field.setText("8434"); |
|
49 |
71 |
|
50 |
72 |
JLabel root_label = new JLabel("Web Root:", JLabel.TRAILING); |
51 |
|
|
73 |
root_field = new JTextField(15); |
|
74 |
root_field.setText("placebohttp.jar/www"); |
|
75 |
||
76 |
JLabel debug_label = new JLabel("Debug:", JLabel.TRAILING); |
|
77 |
debug_field = new JCheckBox(); |
|
52 |
78 |
|
53 |
79 |
start_btn = new JButton("Start Server"); |
54 |
80 |
start_btn.setActionCommand("start"); |
| … | … | @@ -63,6 +89,8 @@ public class ControlPanel extends JFrame |
63 |
89 |
pane.add(port_field); |
64 |
90 |
pane.add(root_label); |
65 |
91 |
pane.add(root_field); |
92 |
pane.add(debug_label); |
|
93 |
pane.add(debug_field); |
|
66 |
94 |
main_pane.add(pane); |
67 |
95 |
|
68 |
96 |
JPanel button_pane = new JPanel(new GridLayout(0,2,6,6)); |
| … | … | @@ -74,7 +102,8 @@ public class ControlPanel extends JFrame |
74 |
102 |
|
75 |
103 |
// Right Side |
76 |
104 |
|
77 |
|
|
105 |
log_box = new JTextArea(); |
|
106 |
log_output = new JTextAreaOutputStream(log_box); |
|
78 |
107 |
JScrollPane scroller = new JScrollPane(log_box); |
79 |
108 |
scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); |
80 |
109 |
tabbed.addTab("Server Log", null, scroller, ""); |
| … | … | @@ -91,11 +120,18 @@ public class ControlPanel extends JFrame |
91 |
120 |
{ |
92 |
121 |
start_btn.setEnabled(false); |
93 |
122 |
stop_btn.setEnabled(true); |
123 |
core = new CoreServer(); |
|
124 |
core.setPort(Integer.valueOf(port_field.getText()).intValue()); |
|
125 |
core.setWebRoot(root_field.getText()); |
|
126 |
core.setDebug(debug_field.isSelected()); |
|
127 |
core.setDebugStream(log_output); |
|
128 |
core.start(); |
|
94 |
129 |
} |
95 |
130 |
if ("stop".equals(e.getActionCommand())) |
96 |
131 |
{ |
132 |
stop_btn.setEnabled(false); |
|
133 |
core.quit(); |
|
97 |
134 |
start_btn.setEnabled(true); |
98 |
stop_btn.setEnabled(false); |
|
99 |
135 |
} |
100 |
136 |
} |
101 |
137 |
} |
Up to file-list src/org/openstatic/placebo/CoreServer.java:
| … | … | @@ -5,6 +5,7 @@ import org.openstatic.http.HttpResponse; |
5 |
5 |
import org.openstatic.http.HttpRequest; |
6 |
6 |
import java.io.File; |
7 |
7 |
import java.io.InputStream; |
8 |
import java.io.OutputStream; |
|
8 |
9 |
import java.io.FileInputStream; |
9 |
10 |
import java.net.URL; |
10 |
11 |
import java.util.zip.ZipFile; |
| … | … | @@ -12,133 +13,179 @@ import java.util.zip.ZipEntry; |
12 |
13 |
import java.util.StringTokenizer; |
13 |
14 |
import java.util.Properties; |
14 |
15 |
|
15 |
public class CoreServer |
|
16 |
public class CoreServer extends Thread |
|
16 |
17 |
{ |
17 |
p |
|
18 |
private int http_port; |
|
19 |
private String web_root; |
|
20 |
private boolean debug; |
|
21 |
private OutputStream debug_out; |
|
22 |
private boolean keep_running; |
|
23 |
private PlaceboHttpServer server; |
|
24 |
||
25 |
public CoreServer() |
|
26 |
{ |
|
27 |
this.http_port = 80; |
|
28 |
this.web_root = "."; |
|
29 |
this.debug_out = System.err; |
|
30 |
this.keep_running = true; |
|
31 |
this.debug = false; |
|
32 |
this.server = new PlaceboHttpServer(http_port); |
|
33 |
} |
|
34 |
||
35 |
public void setPort(int value) |
|
36 |
{ |
|
37 |
this.http_port = value; |
|
38 |
} |
|
39 |
||
40 |
public void setDebug(boolean value) |
|
41 |
{ |
|
42 |
this.debug = value; |
|
43 |
} |
|
44 |
||
45 |
public void setWebRoot(String value) |
|
46 |
{ |
|
47 |
this.web_root = value; |
|
48 |
} |
|
49 |
||
50 |
public void setDebugStream(OutputStream value) |
|
51 |
{ |
|
52 |
this.debug_out = value; |
|
53 |
} |
|
54 |
||
55 |
public void quit() |
|
56 |
{ |
|
57 |
this.keep_running = false; |
|
58 |
server.shutdown(); |
|
59 |
this.interrupt(); |
|
60 |
} |
|
61 |
||
62 |
public void run() |
|
18 |
63 |
{ |
19 |
64 |
// Create new server object |
20 |
PlaceboHttpServer server = new PlaceboHttpServer(http_port); |
|
21 |
65 |
server.setDebug(debug); |
22 |
||
66 |
server.setDebugStream(debug_out); |
|
67 |
server.setPort(this.http_port); |
|
23 |
68 |
// Launch thread. |
24 |
69 |
server.start(); |
25 |
||
26 |
while (true) |
|
70 |
this.keep_running = true; |
|
71 |
while (this.keep_running) |
|
27 |
72 |
{ |
28 |
73 |
// Blocks until request is made to http server. |
29 |
74 |
HttpRequest request = server.getNextRequest(); |
30 |
75 |
|
31 |
// create new response object |
|
32 |
HttpResponse response = new HttpResponse(); |
|
33 |
String path = web_root + request.getPath(); |
|
34 |
||
35 |
// add index to the path if needed |
|
36 |
if (path.endsWith("/")) |
|
76 |
if (request != null) |
|
37 |
77 |
{ |
38 |
path += "index.html"; |
|
39 |
} |
|
40 |
||
41 |
// this wacky thing is for finding out if we are inside a zip |
|
42 |
// and retrieving the proper content. |
|
43 |
StringTokenizer path_tokens = new StringTokenizer(path, "/"); |
|
44 |
boolean in_file = false; |
|
45 |
String in_file_path = ""; |
|
46 |
String in_file_type = ""; |
|
47 |
StringBuffer new_path = new StringBuffer(); |
|
48 |
StringBuffer path_inside_file = new StringBuffer(); |
|
49 |
||
50 |
// fix for beginning "/" |
|
51 |
if (path.startsWith("/")) |
|
52 |
new_path.append("/"); |
|
53 |
||
54 |
while (path_tokens.hasMoreTokens()) |
|
55 |
{ |
|
56 |
String token = path_tokens.nextToken(); |
|
57 |
new_path.append(token); |
|
78 |
// create new response object |
|
79 |
HttpResponse response = new HttpResponse(); |
|
80 |
String path = web_root + request.getPath(); |
|
58 |
81 |
|
59 |
||
60 |
if (in_file) |
|
82 |
// add index to the path if needed |
|
83 |
if (path.endsWith("/")) |
|
61 |
84 |
{ |
62 |
path |
|
85 |
path += "index.html"; |
|
63 |
86 |
} |
64 |
87 |
|
65 |
// files can act like directories sorta |
|
66 |
String lc_token = token.toLowerCase(); |
|
67 |
int dot_loc = lc_token.indexOf("."); |
|
68 |
if (dot_loc > -1 && lc_token.length() > 2 && !in_file) |
|
88 |
// this wacky thing is for finding out if we are inside a zip |
|
89 |
// and retrieving the proper content. |
|
90 |
StringTokenizer path_tokens = new StringTokenizer(path, "/"); |
|
91 |
boolean in_file = false; |
|
92 |
String in_file_path = ""; |
|
93 |
String in_file_type = ""; |
|
94 |
StringBuffer new_path = new StringBuffer(); |
|
95 |
StringBuffer path_inside_file = new StringBuffer(); |
|
96 |
||
97 |
// fix for beginning "/" |
|
98 |
if (path.startsWith("/")) |
|
99 |
new_path.append("/"); |
|
100 |
||
101 |
while (path_tokens.hasMoreTokens()) |
|
69 |
102 |
{ |
70 |
in_file_path = new_path.toString(); |
|
71 |
in_file_type = lc_token.substring(dot_loc+1).toLowerCase(); |
|
72 |
in_file = true; |
|
73 |
} |
|
74 |
||
75 |
// are we done traveling the path |
|
76 |
if (!path_tokens.hasMoreTokens()) |
|
77 |
{ |
|
78 |
|
|
103 |
String token = path_tokens.nextToken(); |
|
104 |
new_path.append(token); |
|
105 |
||
106 |
||
107 |
if (in_file) |
|
79 |
108 |
{ |
80 |
String file_internal_path = path_inside_file.toString(); |
|
81 |
if (in_file && !"".equals(file_internal_path)) |
|
82 |
{ // we are in a path that requires special processing |
|
83 |
||
84 |
// handle paths with zip files |
|
85 |
if (in_file_type.equals("zip") || in_file_type.equals("jar") || in_file_type.equals("war")) |
|
86 |
{ |
|
87 |
String ftype_upper = in_file_type.toUpperCase(); |
|
88 |
server.logln(ftype_upper + " File: " + in_file_path); |
|
89 |
server.logln(ftype_upper + " Resource: " + file_internal_path); |
|
90 |
ZipFile zipfile = new ZipFile(new File(in_file_path)); |
|
91 |
ZipEntry ze = zipfile.getEntry(file_internal_path); |
|
92 |
InputStream zeis = zipfile.getInputStream(ze); |
|
93 |
response.setBufferedData(zeis, HttpResponse.getContentTypeFor(file_internal_path)); |
|
109 |
path_inside_file.append(token); |
|
110 |
} |
|
111 |
||
112 |
// files can act like directories sorta |
|
113 |
String lc_token = token.toLowerCase(); |
|
114 |
int dot_loc = lc_token.indexOf("."); |
|
115 |
if (dot_loc > -1 && lc_token.length() > 2 && !in_file) |
|
116 |
{ |
|
117 |
in_file_path = new_path.toString(); |
|
118 |
in_file_type = lc_token.substring(dot_loc+1).toLowerCase(); |
|
119 |
in_file = true; |
|
120 |
} |
|
121 |
||
122 |
// are we done traveling the path |
|
123 |
if (!path_tokens.hasMoreTokens()) |
|
124 |
{ |
|
125 |
try |
|
126 |
{ |
|
127 |
String file_internal_path = path_inside_file.toString(); |
|
128 |
if (in_file && !"".equals(file_internal_path)) |
|
129 |
{ // we are in a path that requires special processing |
|
130 |
||
131 |
// handle paths with zip files |
|
132 |
if (in_file_type.equals("zip") || in_file_type.equals("jar") || in_file_type.equals("war")) |
|
133 |
{ |
|
134 |
String ftype_upper = in_file_type.toUpperCase(); |
|
135 |
server.logln(ftype_upper + " File: " + in_file_path); |
|
136 |
server.logln(ftype_upper + " Resource: " + file_internal_path); |
|
137 |
ZipFile zipfile = new ZipFile(new File(in_file_path)); |
|
138 |
ZipEntry ze = zipfile.getEntry(file_internal_path); |
|
139 |
InputStream zeis = zipfile.getInputStream(ze); |
|
140 |
response.setBufferedData(zeis, HttpResponse.getContentTypeFor(file_internal_path)); |
|
141 |
} |
|
142 |
||
143 |
// handle ini files |
|
144 |
if (in_file_type.equals("ini")) |
|
145 |
{ |
|
146 |
server.logln("INI File: " + in_file_path); |
|
147 |
server.logln("INI Resource: " + file_internal_path); |
|
148 |
Properties pini = new Properties(); |
|
149 |
pini.load(new FileInputStream(new File(in_file_path))); |
|
150 |
String proxy_url = pini.getProperty("proxy_url"); |
|
151 |
String buffered_proxy_url = pini.getProperty("buffered_proxy_url"); |
|
152 |
||
153 |
if (proxy_url != null) |
|
154 |
{ |
|
155 |
||
156 |
String proxy_path = proxy_url + file_internal_path; |
|
157 |
server.logln("Proxy Path: " + proxy_path); |
|
158 |
response.setData(new URL(proxy_path)); |
|
159 |
||
160 |
} else if (buffered_proxy_url != null) { |
|
161 |
||
162 |
String proxy_path = buffered_proxy_url + file_internal_path; |
|
163 |
server.logln("Buffered Proxy Path: " + proxy_path); |
|
164 |
response.setBufferedData(new URL(proxy_path)); |
|
165 |
||
166 |
} |
|
167 |
} |
|
168 |
||
169 |
} else { // we just have a normal file to serve |
|
170 |
String file_final_path = new_path.toString(); |
|
171 |
server.logln("File: " + file_final_path); |
|
172 |
response.setData(new File(file_final_path)); |
|
94 |
173 |
} |
95 |
||
96 |
// handle ini files |
|
97 |
if (in_file_type.equals("ini")) |
|
98 |
{ |
|
99 |
server.logln("INI File: " + in_file_path); |
|
100 |
server.logln("INI Resource: " + file_internal_path); |
|
101 |
Properties pini = new Properties(); |
|
102 |
pini.load(new FileInputStream(new File(in_file_path))); |
|
103 |
String proxy_url = pini.getProperty("proxy_url"); |
|
104 |
String buffered_proxy_url = pini.getProperty("buffered_proxy_url"); |
|
105 |
||
106 |
if (proxy_url != null) |
|
107 |
{ |
|
108 |
||
109 |
String proxy_path = proxy_url + file_internal_path; |
|
110 |
server.logln("Proxy Path: " + proxy_path); |
|
111 |
response.setData(new URL(proxy_path)); |
|
112 |
||
113 |
} else if (buffered_proxy_url != null) { |
|
114 |
||
115 |
String proxy_path = buffered_proxy_url + file_internal_path; |
|
116 |
server.logln("Buffered Proxy Path: " + proxy_path); |
|
117 |
response.setBufferedData(new URL(proxy_path)); |
|
118 |
||
119 |
} |
|
120 |
} |
|
121 |
||
122 |
} else { // we just have a normal file to serve |
|
123 |
String file_final_path = new_path.toString(); |
|
124 |
server.logln("File: " + file_final_path); |
|
125 |
|
|
174 |
} catch (Exception n) { |
|
175 |
System.err.println(n.getMessage()); |
|
176 |
n.printStackTrace(System.err); |
|
126 |
177 |
} |
127 |
} catch (Exception n) { |
|
128 |
System.err.println(n.getMessage()); |
|
129 |
n.printStackTrace(System.err); |
|
130 |
} |
|
131 |
} else { |
|
132 |
new_path.append("/"); |
|
133 |
if (in_file && path_inside_file.length() > 0) |
|
134 |
{ |
|
135 |
|
|
178 |
} else { |
|
179 |
new_path.append("/"); |
|
180 |
if (in_file && path_inside_file.length() > 0) |
|
181 |
{ |
|
182 |
path_inside_file.append("/"); |
|
183 |
} |
|
136 |
184 |
} |
137 |
185 |
} |
186 |
// deliver response to request |
|
187 |
request.sendResponse(response); |
|
138 |
188 |
} |
139 |
||
140 |
// deliver response to request |
|
141 |
request.sendResponse(response); |
|
142 |
189 |
} |
143 |
190 |
} |
144 |
191 |
} |
