2
// Mono.ASPNET.InitialWorkerRequest
5
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
7
// (C) 2003 Ximian, Inc (http://www.ximian.com)
8
// (C) Copyright 2004 Novell, Inc
10
// Permission is hereby granted, free of charge, to any person obtaining
11
// a copy of this software and associated documentation files (the
12
// "Software"), to deal in the Software without restriction, including
13
// without limitation the rights to use, copy, modify, merge, publish,
14
// distribute, sublicense, and/or sell copies of the Software, and to
15
// permit persons to whom the Software is furnished to do so, subject to
16
// the following conditions:
18
// The above copyright notice and this permission notice shall be
19
// included in all copies or substantial portions of the Software.
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Collections;
31
using System.Configuration;
34
using System.Net.Sockets;
40
public class RequestData
44
public string PathInfo;
45
public string QueryString;
46
public string Protocol;
47
public byte [] InputBuffer;
49
public RequestData (string verb, string path, string queryString, string protocol)
53
this.QueryString = queryString;
54
this.Protocol = protocol;
57
public override string ToString ()
59
StringBuilder sb = new StringBuilder ();
60
sb.AppendFormat ("Verb: {0}\n", Verb);
61
sb.AppendFormat ("Path: {0}\n", Path);
62
sb.AppendFormat ("PathInfo: {0}\n", PathInfo);
63
sb.AppendFormat ("QueryString: {0}\n", QueryString);
64
return sb.ToString ();
68
class RequestLineException : ApplicationException {
69
public RequestLineException () : base ("Error reading request line")
74
public class InitialWorkerRequest
87
const int BSize = 1024 * 32;
89
static Stack bufferStack = new Stack ();
91
static byte [] AllocateBuffer ()
94
if (bufferStack.Count != 0)
95
return (byte []) bufferStack.Pop ();
97
return new byte [BSize];
100
static void FreeBuffer (byte [] buf)
103
bufferStack.Push (buf);
107
public InitialWorkerRequest (NetworkStream ns)
110
throw new ArgumentNullException ("ns");
117
inputBuffer = AllocateBuffer ();
118
inputLength = stream.Read (inputBuffer, 0, BSize);
119
if (inputLength == 0) // Socket closed
120
throw new IOException ("socket closed");
128
if (inputBuffer == null)
131
if (position >= inputLength)
132
return stream.ReadByte ();
134
return (int) inputBuffer [position++];
139
bool foundCR = false;
140
StringBuilder text = new StringBuilder ();
143
int c = ReadInputByte ();
145
if (c == -1) { // end of stream
146
if (text.Length == 0)
155
if (c == '\n') { // newline
156
if ((text.Length > 0) && (text [text.Length - 1] == '\r'))
161
} else if (foundCR) {
170
text.Append ((char) c);
171
if (text.Length > 8192)
172
throw new InvalidOperationException ("Input line too long.");
175
return text.ToString ();
178
bool GetRequestLine ()
190
string [] s = req.Split (' ');
194
verb = s [0].Trim ();
195
path = s [1].Trim ();
198
verb = s [0].Trim ();
199
path = s [1].Trim ();
200
protocol = s [2].Trim ();
206
int qmark = path.IndexOf ('?');
208
queryString = path.Substring (qmark + 1);
209
path = path.Substring (0, qmark);
212
path = HttpUtility.UrlDecode (path);
213
path = GetSafePath (path);
215
// Yes, MS only looks for the '.'. Try setting a handler for
216
// something not containing a '.' and you won't get path_info.
217
int dot = path.LastIndexOf ('.');
218
int slash = (dot != -1) ? path.IndexOf ('/', dot) : -1;
219
if (dot >= 0 && slash >= 0) {
220
pathInfo = path.Substring (slash);
221
path = path.Substring (0, slash);
226
if (path.StartsWith ("/~/")) {
227
// Not sure about this. It makes request such us /~/dir/file work
228
path = path.Substring (2);
234
string GetSafePath (string path)
237
if (path.EndsWith ("/"))
240
path = HttpUtility.UrlDecode (path);
241
path = path.Replace ('\\','/');
242
while (path.IndexOf ("//") != -1)
243
path = path.Replace ("//", "/");
245
string [] parts = path.Split ('/');
246
ArrayList result = new ArrayList (parts.Length);
248
int end = parts.Length;
249
for (int i = 0; i < end; i++) {
250
string current = parts [i];
251
if (current == "" || current == "." )
254
if (current == "..") {
255
if (result.Count > 0)
256
result.RemoveAt (result.Count - 1);
260
result.Add (current);
263
if (result.Count == 0)
266
result.Insert (0, "");
267
return String.Join ("/", (string []) result.ToArray (typeof (string))) + trail;
270
public void ReadRequestData ()
272
if (!GetRequestLine ())
273
throw new RequestLineException ();
275
if (protocol == null) {
276
protocol = "HTTP/1.0";
280
public bool GotSomeInput {
281
get { return gotSomeInput; }
284
public RequestData RequestData {
286
RequestData rd = new RequestData (verb, path, queryString, protocol);
287
byte [] buffer = new byte [inputLength - position];
288
Buffer.BlockCopy (inputBuffer, position, buffer, 0, inputLength - position);
289
rd.InputBuffer = buffer;
290
rd.PathInfo = pathInfo;
291
FreeBuffer (inputBuffer);