• R/O
  • SSH
  • HTTPS

relations: コミット


コミットメタ情報

リビジョン35 (tree)
日時2013-09-28 07:29:42
作者y-moriguchi

ログメッセージ

tiny HTTP server included

変更サマリ

差分

--- relations/src/net/morilib/httpd/HTTPDispatch.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPDispatch.java (revision 35)
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.io.PrintWriter;
20+import java.nio.charset.Charset;
21+
22+/**
23+ *
24+ *
25+ *
26+ * @author MORIGUCHI, Yuichiro 2013/09/28
27+ */
28+public interface HTTPDispatch {
29+
30+ /**
31+ *
32+ * @return
33+ */
34+ public Charset getCharset();
35+
36+ /**
37+ *
38+ * @param r
39+ * @param req
40+ * @throws IOException
41+ */
42+ public void execute(HTTPRequest r,
43+ PrintWriter w) throws IOException;
44+
45+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPLogger.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPLogger.java (revision 35)
@@ -0,0 +1,109 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.util.logging.Level;
19+
20+/**
21+ *
22+ *
23+ *
24+ * @author MORIGUCHI, Yuichiro 2013/09/28
25+ */
26+public abstract class HTTPLogger {
27+
28+ protected Level level = Level.ALL;
29+
30+ public Level getLevel() {
31+ return level;
32+ }
33+
34+ public void setLevel(Level level) {
35+ this.level = level;
36+ }
37+
38+ /**
39+ *
40+ * @param level
41+ * @param format
42+ * @param o
43+ */
44+ public abstract void log(Level level, String format, Object... o);
45+
46+ /**
47+ *
48+ * @param format
49+ * @param os
50+ */
51+ public void severe(String format, Object... os) {
52+ log(Level.SEVERE, format, os);
53+ }
54+
55+ /**
56+ *
57+ * @param format
58+ * @param os
59+ */
60+ public void warning(String format, Object... os) {
61+ log(Level.WARNING, format, os);
62+ }
63+
64+ /**
65+ *
66+ * @param format
67+ * @param os
68+ */
69+ public void info(String format, Object... os) {
70+ log(Level.INFO, format, os);
71+ }
72+
73+ /**
74+ *
75+ * @param format
76+ * @param os
77+ */
78+ public void config(String format, Object... os) {
79+ log(Level.CONFIG, format, os);
80+ }
81+
82+ /**
83+ *
84+ * @param format
85+ * @param os
86+ */
87+ public void fine(String format, Object... os) {
88+ log(Level.FINE, format, os);
89+ }
90+
91+ /**
92+ *
93+ * @param format
94+ * @param os
95+ */
96+ public void finer(String format, Object... os) {
97+ log(Level.FINER, format, os);
98+ }
99+
100+ /**
101+ *
102+ * @param format
103+ * @param os
104+ */
105+ public void finest(String format, Object... os) {
106+ log(Level.FINEST, format, os);
107+ }
108+
109+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPUtils.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPUtils.java (revision 35)
@@ -0,0 +1,109 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.io.PrintWriter;
20+import java.nio.ByteBuffer;
21+import java.nio.channels.SocketChannel;
22+
23+/**
24+ *
25+ *
26+ *
27+ * @author MORIGUCHI, Yuichiro 2013/09/28
28+ */
29+public final class HTTPUtils {
30+
31+ private static final String MSG200 =
32+ "HTTP/1.0 200 OK\r\n";
33+ private static final String MSG400 =
34+ "HTTP/1.0 400 Bad Request\r\n";
35+ private static final String MSG404 =
36+ "HTTP/1.0 404 Not Found\r\n";
37+ private static final String MSG500 =
38+ "HTTP/1.0 500 Internal Error\r\n";
39+
40+ static final Ecrire MESSAGE400 = new Ecrire() {
41+
42+ @Override
43+ public void write(SocketChannel c) throws IOException {
44+ HTTPUtils.putBadRequest(c);
45+ c.close();
46+ }
47+
48+ };
49+
50+ static final Ecrire MESSAGE404 = new Ecrire() {
51+
52+ @Override
53+ public void write(SocketChannel c) throws IOException {
54+ HTTPUtils.putNotFound(c);
55+ c.close();
56+ }
57+
58+ };
59+
60+ static final Ecrire MESSAGE500 = new Ecrire() {
61+
62+ @Override
63+ public void write(SocketChannel c) throws IOException {
64+ HTTPUtils.putBadRequest(c);
65+ c.close();
66+ }
67+
68+ };
69+
70+ private HTTPUtils() {}
71+
72+ public static void puterror(SocketChannel c,
73+ Throwable e) throws IOException {
74+ c.write(ByteBuffer.wrap(MSG500.getBytes()));
75+ }
76+
77+ public static void putApplicationError(PrintWriter w,
78+ Throwable e) throws IOException {
79+ w.println("<html>");
80+ w.println("<head>");
81+ w.println("<title>500 Internal Error</title>");
82+ w.println("</head>");
83+ w.println("<body>");
84+ w.println("<h1>500 Internal Error</h1>");
85+ w.println("<pre>");
86+ e.printStackTrace(w);
87+ w.println("</pre>");
88+ w.println("</body>");
89+ w.println("</html>");
90+ }
91+
92+ public static void putOk(SocketChannel c) throws IOException {
93+ c.write(ByteBuffer.wrap(MSG200.getBytes()));
94+ }
95+
96+ public static void putBadRequest(SocketChannel c) throws IOException {
97+ c.write(ByteBuffer.wrap(MSG400.getBytes()));
98+ }
99+
100+ public static void putNotFound(SocketChannel c) throws IOException {
101+ c.write(ByteBuffer.wrap(MSG404.getBytes()));
102+ }
103+
104+ public static void put(SocketChannel c,
105+ String s) throws IOException {
106+ c.write(ByteBuffer.wrap(s.getBytes()));
107+ }
108+
109+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/URLEncodedInputStream.java (nonexistent)
+++ relations/src/net/morilib/httpd/URLEncodedInputStream.java (revision 35)
@@ -0,0 +1,93 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.io.InputStream;
20+
21+/**
22+ *
23+ *
24+ *
25+ * @author MORIGUCHI, Yuichiro 2013/09/28
26+ */
27+public class URLEncodedInputStream extends InputStream {
28+
29+ private static enum S { INI, P01, P02 }
30+
31+ private S etat = S.INI;
32+ private InputStream ins;
33+
34+ /**
35+ *
36+ * @param ins
37+ */
38+ public URLEncodedInputStream() {
39+ this.ins = null;
40+ }
41+
42+ /**
43+ *
44+ * @param ins
45+ * @throws IOException
46+ */
47+ public void newInputStream(InputStream ins) throws IOException {
48+ if(this.ins != null) this.ins.close();
49+ this.ins = ins;
50+ }
51+
52+ @Override
53+ public int read() throws IOException {
54+ int c, r = 0;
55+
56+ if(ins == null) throw new IllegalStateException();
57+ while(true) {
58+ c = ins.read();
59+ switch(etat) {
60+ case INI:
61+ if(c < 0) {
62+ return -1;
63+ } else if(c == '+') {
64+ return ' ';
65+ } else if(c == '%') {
66+ etat = S.P01; r = 0;
67+ break;
68+ } else {
69+ return c;
70+ }
71+ case P01:
72+ if(c >= '0' && c <= '9') {
73+ etat = S.P02; r = c - '0';
74+ break;
75+ } else {
76+ return '%';
77+ }
78+ case P02:
79+ if(c >= '0' && c <= '9') {
80+ return r * 10 + (c - '0');
81+ } else {
82+ return '%';
83+ }
84+ }
85+ }
86+ }
87+
88+ @Override
89+ public void close() throws IOException {
90+ ins.close();
91+ }
92+
93+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/ResourceEcrire.java (nonexistent)
+++ relations/src/net/morilib/httpd/ResourceEcrire.java (revision 35)
@@ -0,0 +1,61 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.BufferedInputStream;
19+import java.io.IOException;
20+import java.io.InputStream;
21+import java.nio.ByteBuffer;
22+import java.nio.channels.SocketChannel;
23+
24+/**
25+ *
26+ *
27+ *
28+ * @author MORIGUCHI, Yuichiro 2013/09/28
29+ */
30+public class ResourceEcrire implements Ecrire {
31+
32+ private String path;
33+
34+ public ResourceEcrire(String path) {
35+ this.path = path;
36+ }
37+
38+ @Override
39+ public void write(SocketChannel c) throws IOException {
40+ byte[] a = new byte[1024];
41+ InputStream ins = null;
42+ int l;
43+
44+ try {
45+ ins = HTTPServer.class.getResourceAsStream("/" + path);
46+ if(ins == null) {
47+ HTTPUtils.putNotFound(c);
48+ } else {
49+ HTTPUtils.putOk(c);
50+ HTTPUtils.put(c, "\r\n");
51+ ins = new BufferedInputStream(ins);
52+ while((l = ins.read(a)) >= 0) {
53+ c.write(ByteBuffer.wrap(a, 0, l));
54+ }
55+ }
56+ } finally {
57+ if(ins != null) ins.close();
58+ }
59+ }
60+
61+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPServer.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPServer.java (revision 35)
@@ -0,0 +1,201 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.ByteArrayInputStream;
19+import java.io.IOException;
20+import java.net.InetSocketAddress;
21+import java.nio.ByteBuffer;
22+import java.nio.channels.SelectionKey;
23+import java.nio.channels.Selector;
24+import java.nio.channels.ServerSocketChannel;
25+import java.nio.channels.SocketChannel;
26+import java.nio.charset.Charset;
27+import java.util.HashMap;
28+import java.util.Iterator;
29+import java.util.Map;
30+import java.util.regex.Matcher;
31+import java.util.regex.Pattern;
32+
33+/**
34+ *
35+ *
36+ * @author MORIGUCHI, Yuichiro 2013/09/28
37+ */
38+public class HTTPServer {
39+
40+ private static final int PORT = 9393;
41+ private static final int BUFSIZE = 1024;
42+
43+ private static Pattern PN1 = Pattern.compile(
44+ "(/([^\\?]+/)*([^/\\.\\?]+(\\.([^/\\.\\?]+))?)?)(\\?.*)?$");
45+
46+ static HTTPLogger log = new HTTPLoggerFactory.L();
47+
48+ private Map<SelectionKey, HTTPRequestContinuableParser> wait =
49+ new HashMap<SelectionKey, HTTPRequestContinuableParser>();
50+ private Map<SelectionKey, Ecrire> ecrire =
51+ new HashMap<SelectionKey, Ecrire>();
52+ private Map<String, HTTPDispatch> dispatchers =
53+ new HashMap<String, HTTPDispatch>();
54+ private Charset cset;
55+ private String root;
56+
57+ /**
58+ *
59+ * @param root
60+ */
61+ public HTTPServer(String root) {
62+ this.root = root;
63+ this.cset = Charset.defaultCharset();
64+ }
65+
66+ Ecrire dispatch(SelectionKey k, HTTPRequest q) throws IOException {
67+ HTTPDispatch d;
68+ Class<?> c;
69+ Matcher m;
70+ String s;
71+
72+ log.finest("method: %s", q.getMethod());
73+ log.finest("path: %s", q.getPath());
74+ log.finest("version: %s", q.getVersion());
75+ try {
76+ s = q.getPath();
77+ if(!(m = PN1.matcher(s)).find()) {
78+ log.finest("400: %s", s);
79+ return HTTPUtils.MESSAGE400;
80+ } else if(m.group(3) == null) {
81+ // index.html
82+ log.finest("directory: %s", s);
83+ return new ResourceEcrire(root + s + "index.html");
84+ } else if(m.group(4) != null) {
85+ // resource
86+ log.finest("file: %s", s);
87+ return new ResourceEcrire(root + s);
88+ } else {
89+ // dynamic
90+ log.finest("dynamic: %s", s);
91+ s = (root + s).replace('/', '.');
92+ c = Class.forName(s);
93+ if((d = dispatchers.get(s)) == null) {
94+ d = (HTTPDispatch)c.newInstance();
95+ dispatchers.put(s, d);
96+ }
97+ return new DynamicEcrire(d, q, c);
98+ }
99+ } catch(Exception e) {
100+ log.finest("exception read(): %s", e.toString());
101+ return HTTPUtils.MESSAGE500;
102+ }
103+ }
104+
105+ void accept(Selector s,
106+ ServerSocketChannel c) throws IOException {
107+ SocketChannel d;
108+
109+ d = c.accept();
110+ d.configureBlocking(false);
111+ d.register(s, SelectionKey.OP_READ);
112+ }
113+
114+ void read(SelectionKey k) throws IOException {
115+ SocketChannel c = (SocketChannel)k.channel();
116+ ByteBuffer b = ByteBuffer.allocate(BUFSIZE);
117+ HTTPRequestContinuableParser s = null;
118+ HTTPRequest q;
119+ Ecrire w;
120+ byte[] a;
121+
122+ s = wait.get(k);
123+ while(c.read(b) > 0) {
124+ if(s == null) {
125+ s = new HTTPRequestContinuableParser(cset);
126+ wait.put(k, s);
127+ }
128+ b.flip(); a = new byte[b.limit()]; b.get(a);
129+ log.finest("\"%s\"", new String(a, cset));
130+ s.readPartial(new ByteArrayInputStream(a));
131+ }
132+
133+ if(s == null) {
134+ k.cancel(); c.close();
135+ } else {
136+ log.finest("read end of request");
137+ wait.remove(k);
138+ q = s.getRequest();
139+ w = dispatch(k, q);
140+ k.interestOps(k.interestOps() | SelectionKey.OP_WRITE);
141+ ecrire.put(k, w);
142+ log.finest("ready to response");
143+ }
144+ }
145+
146+ void write(SelectionKey k) throws IOException {
147+ SocketChannel c = (SocketChannel)k.channel();
148+ Ecrire w;
149+
150+ try {
151+ if((w = ecrire.get(k)) != null) {
152+ log.finest("ecrire found");
153+ w.write(c);
154+ } else {
155+ log.finest("ecrire not found");
156+ }
157+ log.finest("responded");
158+ } finally {
159+ k.cancel(); c.close();
160+ }
161+ }
162+
163+ public void serve() throws IOException {
164+ ServerSocketChannel c = null;
165+ Iterator<SelectionKey> i;
166+ SelectionKey k;
167+ Selector s;
168+
169+ try {
170+ s = Selector.open();
171+ c = ServerSocketChannel.open();
172+ c.configureBlocking(false);
173+ c.socket().bind(new InetSocketAddress(PORT));
174+ c.register(s, SelectionKey.OP_ACCEPT);
175+ while(s.select() > 0) {
176+ try {
177+ i = s.selectedKeys().iterator();
178+ while(i.hasNext()) {
179+ k = i.next(); i.remove();
180+ if(!k.isValid()) {
181+ // do nothing
182+ } else if(k.isAcceptable()) {
183+ accept(s, (ServerSocketChannel)k.channel());
184+ } else if(k.isReadable()) {
185+ log.finest("begin to read");
186+ read(k);
187+ } else if(k.isWritable()) {
188+ log.finest("begin to write");
189+ write(k);
190+ }
191+ }
192+ } catch(Exception e) {
193+ e.printStackTrace(System.err);
194+ }
195+ }
196+ } finally {
197+ if(c != null && c.isOpen()) c.close();
198+ }
199+ }
200+
201+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPLoggerFactory.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPLoggerFactory.java (revision 35)
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.text.SimpleDateFormat;
19+import java.util.logging.Level;
20+
21+/**
22+ *
23+ *
24+ *
25+ * @author MORIGUCHI, Yuichiro 2013/09/28
26+ */
27+public class HTTPLoggerFactory {
28+
29+ static class L extends HTTPLogger {
30+
31+ public void log(Level l, String format, Object... os) {
32+ java.util.Date d;
33+
34+ if(level.intValue() > l.intValue()) {
35+ // do nothing
36+ } else {
37+ d = new java.util.Date();
38+ System.err.print(FMT.format(d));
39+ System.err.print(" :");
40+ System.err.print(l.toString());
41+ System.err.print(" :");
42+ System.err.format(format, os);
43+ System.err.println();
44+ }
45+ }
46+
47+ };
48+
49+ private static final SimpleDateFormat FMT =
50+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
51+
52+ private static HTTPLogger log = new L();
53+
54+ /**
55+ *
56+ * @return
57+ */
58+ public static HTTPLogger getInstance() {
59+ return log;
60+ }
61+
62+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPRequest.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPRequest.java (revision 35)
@@ -0,0 +1,100 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.util.Collections;
19+import java.util.LinkedHashMap;
20+import java.util.Map;
21+
22+/**
23+ *
24+ *
25+ * @author MORIGUCHI, Yuichiro 2013/09/28
26+ */
27+public class HTTPRequest {
28+
29+ private String method, path, version;
30+ private Map<String, String> headers =
31+ new LinkedHashMap<String, String>();
32+ private Map<String, String> parameters =
33+ new LinkedHashMap<String, String>();
34+
35+ //
36+ HTTPRequest(String m, String a, String v, Map<String, String> h,
37+ Map<String, String> p) {
38+ method = m;
39+ path = a;
40+ version = v;
41+ headers = h;
42+ parameters = p;
43+ }
44+
45+ /**
46+ * @return the method
47+ */
48+ public String getMethod() {
49+ return method;
50+ }
51+
52+ /**
53+ * @return the path
54+ */
55+ public String getPath() {
56+ return path;
57+ }
58+
59+ /**
60+ * @return the version
61+ */
62+ public String getVersion() {
63+ return version;
64+ }
65+
66+ /**
67+ *
68+ * @param key
69+ * @return
70+ */
71+ public String getHeader(String key) {
72+ return headers.get(key);
73+ }
74+
75+ /**
76+ *
77+ * @param key
78+ * @return
79+ */
80+ public String getParameter(String key) {
81+ return parameters.get(key);
82+ }
83+
84+ /**
85+ *
86+ * @return
87+ */
88+ public Map<String, String> getHeaders() {
89+ return Collections.unmodifiableMap(headers);
90+ }
91+
92+ /**
93+ *
94+ * @return
95+ */
96+ public Map<String, String> getParameters() {
97+ return Collections.unmodifiableMap(parameters);
98+ }
99+
100+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/Ecrire.java (nonexistent)
+++ relations/src/net/morilib/httpd/Ecrire.java (revision 35)
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.nio.channels.SocketChannel;
20+
21+/**
22+ *
23+ *
24+ *
25+ * @author MORIGUCHI, Yuichiro 2013/09/28
26+ */
27+public interface Ecrire {
28+
29+ /**
30+ *
31+ * @param c
32+ */
33+ public void write(SocketChannel c) throws IOException;
34+
35+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/HTTPRequestContinuableParser.java (nonexistent)
+++ relations/src/net/morilib/httpd/HTTPRequestContinuableParser.java (revision 35)
@@ -0,0 +1,249 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.io.InputStream;
20+import java.nio.charset.Charset;
21+import java.util.LinkedHashMap;
22+import java.util.Map;
23+import java.util.regex.Matcher;
24+import java.util.regex.Pattern;
25+
26+/**
27+ *
28+ *
29+ *
30+ * @author MORIGUCHI, Yuichiro 2013/09/28
31+ */
32+public class HTTPRequestContinuableParser {
33+
34+ private static enum S { INIT, HEAD, POST, DONE }
35+
36+ private static Pattern PTN = Pattern.compile(
37+ "([A-Z]+) +([^ ]+) +HTTP/([01].[0-9])");
38+
39+ private Map<String, String> headers =
40+ new LinkedHashMap<String, String>();
41+ private Map<String, String> parameters =
42+ new LinkedHashMap<String, String>();
43+
44+ private URLEncodedInputStream ins;
45+ private StringBuffer buf = new StringBuffer();
46+ private Matcher match = null;
47+ private String key, val;
48+ private Charset enc;
49+ private S state = S.INIT;
50+ private int etat = 0;
51+
52+ /**
53+ *
54+ * @param encoding
55+ */
56+ public HTTPRequestContinuableParser(Charset encoding) {
57+ ins = new URLEncodedInputStream();
58+ key = val = null;
59+ enc = encoding;
60+ }
61+
62+ private void completeString() throws IOException {
63+ String s;
64+
65+ s = buf.toString();
66+ s = new String(s.getBytes("ISO-8859-1"), enc);
67+ if(!(match = PTN.matcher(s)).matches()) {
68+ throw new IOException();
69+ }
70+ buf = new StringBuffer();
71+ etat = 0;
72+ }
73+
74+ boolean readString() throws IOException {
75+ int c;
76+
77+ if(ins == null) throw new IOException();
78+ for(; true; etat = c) {
79+ if((c = ins.read()) < 0) return false;
80+ switch(etat) {
81+ case '\r':
82+ if(c == '\n') {
83+ completeString();
84+ state = S.HEAD;
85+ return true;
86+ } else {
87+ buf.append(etat).appendCodePoint(c);
88+ break;
89+ }
90+ default:
91+ if(c != '\r') buf.appendCodePoint(c);
92+ break;
93+ }
94+ }
95+ }
96+
97+ private boolean completeHeader() throws IOException {
98+ if(key != null) {
99+ val = buf.toString().trim();
100+ } else if(buf.length() > 0) {
101+ key = buf.toString().trim();
102+ } else if(match.group(1).equals("POST")) {
103+ state = S.POST; etat = 0;
104+ return true;
105+ } else {
106+ state = S.DONE; etat = 0;
107+ return true;
108+ }
109+ headers.put(key, val);
110+ key = val = null;
111+ buf = new StringBuffer();
112+ return false;
113+ }
114+
115+ boolean readHeader() throws IOException {
116+ int c;
117+
118+ if(ins == null) {
119+ state = S.DONE;
120+ return false;
121+ }
122+
123+ for(; true; etat = c) {
124+ if((c = ins.read()) < 0) return false;
125+ switch(etat) {
126+ case '\r':
127+ if(c != '\n') {
128+ buf.appendCodePoint(etat).appendCodePoint(c);
129+ break;
130+ } else if(completeHeader()) {
131+ return true;
132+ }
133+ break;
134+ case ':':
135+ if(key == null) {
136+ key = buf.toString().trim();
137+ buf = new StringBuffer();
138+ }
139+ buf.appendCodePoint(c);
140+ break;
141+ default:
142+ if(c != '\r' && !(c == ':' && key == null)) {
143+ buf.appendCodePoint(c);
144+ }
145+ break;
146+ }
147+ }
148+ }
149+
150+ private boolean completeParameters() throws IOException {
151+ if(key != null) {
152+ val = buf.toString().trim();
153+ } else if(buf.length() > 0) {
154+ key = buf.toString().trim();
155+ } else {
156+ state = S.DONE; etat = 0;
157+ return true;
158+ }
159+ parameters.put(key, val == null ? "" : val);
160+ key = val = null;
161+ buf = new StringBuffer();
162+ return false;
163+ }
164+
165+ boolean readParameters() throws IOException {
166+ int c;
167+
168+ for(; true; etat = c) {
169+ if((c = ins.read()) < 0) return false;
170+ switch(etat) {
171+ case '\r':
172+ if(c != '\n') {
173+ buf.appendCodePoint(etat).appendCodePoint(c);
174+ } else if(completeParameters()) {
175+ return true;
176+ }
177+ break;
178+ case '=':
179+ if(key == null) {
180+ key = buf.toString().trim();
181+ buf = new StringBuffer();
182+ }
183+ buf.appendCodePoint(c);
184+ break;
185+ case '&':
186+ if(key != null) {
187+ val = buf.toString().trim();
188+ } else {
189+ key = buf.toString().trim();
190+ }
191+ parameters.put(key, val == null ? "" : val);
192+ key = val = null;
193+ buf = new StringBuffer().appendCodePoint(c);
194+ break;
195+ default:
196+ if(c != '\r' && c != '&' && c != '=') {
197+ buf.appendCodePoint(c);
198+ }
199+ break;
200+ }
201+ }
202+ }
203+
204+ /**
205+ *
206+ * @return
207+ */
208+ public boolean isDone() {
209+ return state.equals(S.DONE);
210+ }
211+
212+ /**
213+ *
214+ * @return
215+ */
216+ public HTTPRequest getRequest() throws IOException {
217+ switch(state) {
218+ case INIT: completeString(); break;
219+ case HEAD: completeHeader(); break;
220+ case POST: completeParameters(); break;
221+ case DONE: break;
222+ }
223+ state = S.DONE;
224+ return new HTTPRequest(match.group(1), match.group(2),
225+ match.group(3), headers, parameters);
226+ }
227+
228+ /**
229+ *
230+ * @param ins
231+ * @throws IOException
232+ */
233+ public void readPartial(InputStream in) throws IOException {
234+ boolean b = true;
235+
236+ ins.newInputStream(in);
237+ while(b) {
238+ switch(state) {
239+ case INIT: b = readString(); break;
240+ case HEAD: b = readHeader(); break;
241+ case POST: b = readParameters(); break;
242+ case DONE:
243+ while(ins.read() >= 0);
244+ return;
245+ }
246+ }
247+ }
248+
249+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/Zhttpd.java (nonexistent)
+++ relations/src/net/morilib/httpd/Zhttpd.java (revision 35)
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+
20+/**
21+ *
22+ *
23+ *
24+ * @author MORIGUCHI, Yuichiro 2013/09/28
25+ */
26+public final class Zhttpd {
27+
28+ public static void main(String[] args) {
29+ HTTPServer s;
30+
31+ try {
32+ s = new HTTPServer(args[0].replace('.', '/'));
33+ s.serve();
34+ } catch(IOException e) {
35+ throw new RuntimeException(e);
36+ }
37+ }
38+
39+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- relations/src/net/morilib/httpd/DynamicEcrire.java (nonexistent)
+++ relations/src/net/morilib/httpd/DynamicEcrire.java (revision 35)
@@ -0,0 +1,91 @@
1+/*
2+ * Copyright 2013 Yuichiro Moriguchi
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package net.morilib.httpd;
17+
18+import java.io.IOException;
19+import java.io.PrintWriter;
20+import java.lang.reflect.InvocationTargetException;
21+import java.lang.reflect.Method;
22+import java.nio.channels.Channels;
23+import java.nio.channels.SocketChannel;
24+import java.nio.charset.CharsetEncoder;
25+
26+/**
27+ *
28+ *
29+ *
30+ * @author MORIGUCHI, Yuichiro 2013/09/28
31+ */
32+public class DynamicEcrire implements Ecrire {
33+
34+ private HTTPDispatch dispatch;
35+ private HTTPRequest request;
36+ private Class<?> classe;
37+
38+ /**
39+ *
40+ * @param d
41+ * @param q
42+ * @param k
43+ */
44+ public DynamicEcrire(HTTPDispatch d, HTTPRequest q, Class<?> k) {
45+ dispatch = d;
46+ request = q;
47+ classe = k;
48+ }
49+
50+ @Override
51+ public void write(SocketChannel c) throws IOException {
52+ PrintWriter p = null;
53+ CharsetEncoder o;
54+ Method t;
55+
56+ o = dispatch.getCharset().newEncoder();
57+ p = new PrintWriter(Channels.newWriter(c, o, -1));
58+ try {
59+ HTTPServer.log.finest("DynamicEcrire");
60+ t = classe.getMethod("execute", HTTPRequest.class,
61+ PrintWriter.class);
62+ HTTPUtils.putOk(c);
63+ HTTPUtils.put(c, o.toString());
64+ HTTPUtils.put(c, "\r\n\r\n");
65+ t.invoke(dispatch, request, p);
66+ } catch(SecurityException e) {
67+ HTTPServer.log.finest("exception write(): %s",
68+ e.toString());
69+ HTTPUtils.puterror(c, e);
70+ } catch(NoSuchMethodException e) {
71+ HTTPServer.log.finest("exception write(): %s",
72+ e.toString());
73+ HTTPUtils.puterror(c, e);
74+ } catch(IllegalArgumentException e) {
75+ HTTPServer.log.finest("exception write(): %s",
76+ e.toString());
77+ HTTPUtils.puterror(c, e);
78+ } catch(IllegalAccessException e) {
79+ HTTPServer.log.finest("exception write(): %s",
80+ e.toString());
81+ HTTPUtils.puterror(c, e);
82+ } catch(InvocationTargetException e) {
83+ HTTPServer.log.finest("exception write(): %s",
84+ e.toString());
85+ HTTPUtils.putApplicationError(p, e.getCause());
86+ } finally {
87+ p.flush();
88+ }
89+ }
90+
91+}
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
旧リポジトリブラウザで表示