Allow schema files that are missing checksums on the !!SCHEMAMATIC line.
[versaplex.git] / wvdotnet / wvhttpserver.cs
blob97b3f9a6cb2219183ecd1031a607be45c8abb67f
1 /*
2 * Versaplex:
3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
5 */
6 using System;
7 using System.IO;
8 using System.Net.Sockets;
9 using System.Collections.Specialized;
10 using System.Collections.Generic;
11 using System.Data;
12 using System.Web;
13 using Wv;
14 using Wv.Extensions;
16 namespace Wv
18 public class WvHttpSession : Dictionary<string,string>
20 WvLog log = new WvLog("session");
21 WvDbi dbi;
22 string _sessid;
23 public string sessid { get { return _sessid; } }
25 public WvHttpSession(WvDbi dbi, string sessid)
27 this.dbi = dbi;
28 this._sessid = sessid;
29 load();
32 public WvHttpSession(WvDbi dbi)
34 this.dbi = dbi;
35 this._sessid = new_sessid();
36 dbi.execute("insert into Session (ixSession, dtSaved, bData) "
37 + "values (?, ?, ?) ", sessid, DateTime.Now, "");
40 static string new_sessid()
42 return wv.randombytes(20).ToHex();
45 void load()
47 log.print("Loading session '{0}'\n", sessid);
49 // There should actually be only one row
50 foreach (var r in
51 dbi.select("select dtSaved, bData from Session "
52 + "where ixSession=? ",
53 sessid))
55 DateTime dt = r[0];
56 if (dt + TimeSpan.FromSeconds(60*60) >= DateTime.Now)
57 wv.urlsplit(this, r[1]);
61 public void save()
63 List<string> l = new List<string>();
64 foreach (string k in Keys)
65 l.Add(HttpUtility.UrlEncode(k)
66 + "="
67 + HttpUtility.UrlEncode(this[k]));
68 string data = l.join("&");
70 try
72 dbi.execute("insert into Session (ixSession, dtSaved, bData) "
73 + "values (?, ?, ?)",
74 sessid, DateTime.Now, "");
76 catch { }
78 dbi.execute("update Session set bData=?, dtSaved=? "
79 + "where ixSession=?", data, DateTime.Now, sessid);
83 public interface IWvHttpRequest
85 string request_uri { get; }
86 Web.Cgi.Method request_method { get; }
87 string path { get; }
88 string query_string { get; }
89 Dictionary<string,string> headers { get; }
90 // FIXME: This sucks, it should really be a Dictionary<string,string>
91 // to match the headers, but Wv.Cgi already has this as a
92 // NameValueCollection
93 NameValueCollection request { get; }
96 public class WvHttpRequest : IWvHttpRequest
98 public string _request_uri;
99 public string request_uri
101 get { return _request_uri; }
102 set { _request_uri = value; }
105 public Web.Cgi.Method request_method
107 get { return Web.Cgi.Method.Get; }
110 public string path
112 get { return request_uri.Split(new char[] {'?'}, 2)[0]; }
115 public string query_string
119 string[] parts = request_uri.Split(new char[] {'?'}, 2);
120 if (parts.Length >= 2)
121 return parts[1];
122 else
123 return "";
127 public Dictionary<string,string> _headers
128 = new Dictionary<string,string>();
129 public Dictionary<string,string> headers
131 get { return _headers; }
134 public NameValueCollection request
136 get { return null; }
139 public WvHttpRequest() { }
141 public WvHttpRequest(string s)
143 parse_request(wv.fmt("GET {0} HTTP/1.0", s));
146 public void parse_request(string s)
148 string[] parts = s.Split(new char[] {' '}, 3);
149 if (parts.Length < 3)
150 throw new Exception("Not enough words in request!");
151 if (parts[0] != "GET")
152 throw new Exception("Request should start with GET");
153 request_uri = parts[1];
156 public void parse_header(string s)
158 if (s == "") return;
160 string[] parts = s.Split(new char[] {':'}, 2,
161 StringSplitOptions.None);
162 string key = parts[0].ToLower();
163 headers.Remove(key);
164 if (parts.Length < 2)
165 headers.Add(key, "");
166 else
167 headers.Add(key, parts[1].Trim());
171 public class WvHttpCgiRequest : IWvHttpRequest
173 Web.Cgi cgi;
175 public string request_uri
177 get { return cgi.cgivars["REQUEST_URI"]; }
180 public Web.Cgi.Method request_method
182 get { return cgi.method; }
185 public string path
187 get { return cgi.script_name; }
190 public string query_string
192 get { return cgi.query_string; }
195 public Dictionary<string,string> _headers
196 = new Dictionary<string,string>();
197 public Dictionary<string,string> headers
199 get { return _headers; }
202 public NameValueCollection request
204 get { return cgi.request; }
207 public WvHttpCgiRequest()
209 cgi = new Web.Cgi();
211 foreach (string key in cgi.cgivars)
213 if (key.StartsWith("HTTP_"))
215 // Turn "HTTP_HEADER_NAME" into "header-name"
216 headers.Add(
217 key.Substring(5).ToLower().Replace('_', '-'),
218 cgi.cgivars[key]);
224 public class WvHttpServer
226 TcpListener server;
227 WvLog log = new WvLog("HTTP Server", WvLog.L.Info);
229 public delegate void Responder(WvHttpRequest req, Stream s);
230 Responder responder;
232 public WvHttpServer(int port, Responder responder)
234 this.responder = responder;
235 log.print("World's dumbest http server initializing. (and how!)\n");
236 log.print("Trying port {0}.\n", port);
237 server = new TcpListener(port);
238 server.Start();
239 log.print("Listening on {0}\n", server.LocalEndpoint);
242 public void runonce()
244 TcpClient client = server.AcceptTcpClient();
245 log.print("Incoming connection.\n");
247 NetworkStream stream = client.GetStream();
248 StreamReader r = new StreamReader(stream);
250 WvHttpRequest req = new WvHttpRequest();
251 string s = r.ReadLine();
252 log.print("Got request line: '{0}'\n", s);
253 req.parse_request(s);
254 log.print("Path is: '{0}'\n", req.request_uri);
257 s = r.ReadLine();
258 log.print("Got header line: '{0}'\n", s);
259 req.parse_header(s);
261 while (s != "");
263 responder(req, stream);
265 log.print("Closing connection.\n");
266 client.Close();