aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs269
1 files changed, 269 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs
new file mode 100644
index 0000000..4286586
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs
@@ -0,0 +1,269 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/**
29 * @brief Perform web request
30 */
31
32using System;
33using System.IO;
34using System.Net;
35using System.Text;
36
37namespace OpenSim.Region.ScriptEngine.XMREngine {
38 public class MMRWebRequest {
39 public static bool allowFileURL = false;
40
41 public static Stream MakeRequest (string verb, string requestUrl, string obj, int timeoutms)
42 {
43 /*
44 * Pick apart the given URL and make sure we support it.
45 * For file:// URLs, just return a read-only stream of the file.
46 */
47 Uri uri = new Uri (requestUrl);
48 string supported = "http and https";
49 if (allowFileURL && (verb == "GET")) {
50 supported = "file, http and https";
51 if (uri.Scheme == "file") {
52 return File.OpenRead (requestUrl.Substring (7));
53 }
54 }
55 bool https = uri.Scheme == "https";
56 if (!https && (uri.Scheme != "http")) {
57 throw new WebException ("only support " + supported + ", not " + uri.Scheme + " in " + requestUrl);
58 }
59 string host = uri.Host;
60 int port = uri.Port;
61 if (port < 0) port = https ? 443 : 80;
62 string path = uri.AbsolutePath;
63
64 /*
65 * Connect to the web server.
66 */
67 System.Net.Sockets.TcpClient tcpconnection = new System.Net.Sockets.TcpClient (host, port);
68 if (timeoutms > 0) {
69 tcpconnection.SendTimeout = timeoutms;
70 tcpconnection.ReceiveTimeout = timeoutms;
71 }
72
73 try {
74
75 /*
76 * Get TCP stream to/from web server.
77 * If HTTPS, wrap stream with SSL encryption.
78 */
79 Stream tcpstream = tcpconnection.GetStream ();
80 if (https) {
81 System.Net.Security.SslStream sslstream = new System.Net.Security.SslStream (tcpstream, false);
82 sslstream.AuthenticateAsClient (host);
83 tcpstream = sslstream;
84 }
85
86 /*
87 * Write request header to the web server.
88 * There might be some POST data as well to write to web server.
89 */
90 WriteStream (tcpstream, verb + " " + path + " HTTP/1.1\r\n");
91 WriteStream (tcpstream, "Host: " + host + "\r\n");
92 if (obj != null) {
93 byte[] bytes = Encoding.UTF8.GetBytes (obj);
94
95 WriteStream (tcpstream, "Content-Length: " + bytes.Length + "\r\n");
96 WriteStream (tcpstream, "Content-Type: application/x-www-form-urlencoded\r\n");
97 WriteStream (tcpstream, "\r\n");
98 tcpstream.Write (bytes, 0, bytes.Length);
99 } else {
100 WriteStream (tcpstream, "\r\n");
101 }
102 tcpstream.Flush ();
103
104 /*
105 * Check for successful reply status line.
106 */
107 string headerline = ReadStreamLine (tcpstream).Trim ();
108 if (headerline != "HTTP/1.1 200 OK") throw new WebException ("status line " + headerline);
109
110 /*
111 * Scan through header lines.
112 * The only ones we care about are Content-Length and Transfer-Encoding.
113 */
114 bool chunked = false;
115 int contentlength = -1;
116 while ((headerline = ReadStreamLine (tcpstream).Trim ().ToLowerInvariant ()) != "") {
117 if (headerline.StartsWith ("content-length:")) {
118 contentlength = int.Parse (headerline.Substring (15));
119 }
120 if (headerline.StartsWith ("transfer-encoding:") && (headerline.Substring (18).Trim () == "chunked")) {
121 chunked = true;
122 }
123 }
124
125 /*
126 * Read response byte array as a series of chunks.
127 */
128 if (chunked) {
129 return new ChunkedStreamReader (tcpstream);
130 }
131
132 /*
133 * Read response byte array with the exact length given by Content-Length.
134 */
135 if (contentlength >= 0) {
136 return new LengthStreamReader (tcpstream, contentlength);
137 }
138
139 /*
140 * Don't know how it is being transferred.
141 */
142 throw new WebException ("header missing content-length or transfer-encoding: chunked");
143 } catch {
144 tcpconnection.Close ();
145 throw;
146 }
147 }
148
149 /**
150 * @brief Write the string out as ASCII bytes.
151 */
152 private static void WriteStream (Stream stream, string line)
153 {
154 byte[] bytes = Encoding.ASCII.GetBytes (line);
155 stream.Write (bytes, 0, bytes.Length);
156 }
157
158 /**
159 * @brief Read the next text line from a stream.
160 * @returns string with \r\n trimmed off
161 */
162 private static string ReadStreamLine (Stream stream)
163 {
164 StringBuilder sb = new StringBuilder ();
165 while (true) {
166 int b = stream.ReadByte ();
167 if (b < 0) break;
168 if (b == '\n') break;
169 if (b == '\r') continue;
170 sb.Append ((char)b);
171 }
172 return sb.ToString ();
173 }
174
175 private class ChunkedStreamReader : Stream {
176 private int chunklen;
177 private Stream tcpstream;
178
179 public ChunkedStreamReader (Stream tcpstream)
180 {
181 this.tcpstream = tcpstream;
182 }
183
184 public override bool CanRead { get { return true; } }
185 public override bool CanSeek { get { return false; } }
186 public override bool CanTimeout { get { return false; } }
187 public override bool CanWrite { get { return false; } }
188 public override long Length { get { return 0; } }
189 public override long Position { get { return 0; } set { } }
190 public override void Flush () { }
191 public override long Seek (long offset, SeekOrigin origin) { return 0; }
192 public override void SetLength (long length) { }
193 public override void Write (byte[] buffer, int offset, int length) { }
194
195 public override int Read (byte[] buffer, int offset, int length)
196 {
197 if (length <= 0) return 0;
198
199 if (chunklen == 0) {
200 chunklen = int.Parse (ReadStreamLine (tcpstream), System.Globalization.NumberStyles.HexNumber);
201 if (chunklen < 0) throw new WebException ("negative chunk length");
202 if (chunklen == 0) chunklen = -1;
203 }
204 if (chunklen < 0) return 0;
205
206 int maxread = (length < chunklen) ? length : chunklen;
207 int lenread = tcpstream.Read (buffer, offset, maxread);
208 chunklen -= lenread;
209 if (chunklen == 0) {
210 int b = tcpstream.ReadByte ();
211 if (b == '\r') b = tcpstream.ReadByte ();
212 if (b != '\n') throw new WebException ("chunk not followed by \\r\\n");
213 }
214 return lenread;
215 }
216
217 public override void Close ()
218 {
219 chunklen = -1;
220 if (tcpstream != null) {
221 tcpstream.Close ();
222 tcpstream = null;
223 }
224 }
225 }
226
227 private class LengthStreamReader : Stream {
228 private int contentlength;
229 private Stream tcpstream;
230
231 public LengthStreamReader (Stream tcpstream, int contentlength)
232 {
233 this.tcpstream = tcpstream;
234 this.contentlength = contentlength;
235 }
236
237 public override bool CanRead { get { return true; } }
238 public override bool CanSeek { get { return false; } }
239 public override bool CanTimeout { get { return false; } }
240 public override bool CanWrite { get { return false; } }
241 public override long Length { get { return 0; } }
242 public override long Position { get { return 0; } set { } }
243 public override void Flush () { }
244 public override long Seek (long offset, SeekOrigin origin) { return 0; }
245 public override void SetLength (long length) { }
246 public override void Write (byte[] buffer, int offset, int length) { }
247
248 public override int Read (byte[] buffer, int offset, int length)
249 {
250 if (length <= 0) return 0;
251 if (contentlength <= 0) return 0;
252
253 int maxread = (length < contentlength) ? length : contentlength;
254 int lenread = tcpstream.Read (buffer, offset, maxread);
255 contentlength -= lenread;
256 return lenread;
257 }
258
259 public override void Close ()
260 {
261 contentlength = -1;
262 if (tcpstream != null) {
263 tcpstream.Close ();
264 tcpstream = null;
265 }
266 }
267 }
268 }
269}