Main Page | Class Hierarchy | Class List | File List | Class Members

HTTPResponse.cs

00001 using System;
00002 using System.IO;
00003 using System.Text;
00004 using System.Net.Sockets;
00005 using System.Collections;
00006 using System.Runtime.Serialization;
00007 using System.Runtime.Serialization.Formatters.Binary;
00008 using NZlib.Streams;
00009 
00010 namespace Common {
00011 
00012         /**************************************************************************************************/
00013         public class HTTPResponse : HTTPObject {
00014                 /*** Properties ***/
00015                 public String ContentType {
00016                         get {
00017                                 return headers.headerCollection["Content-Type"];
00018                         }
00019                 }
00020 
00021                 public String ContentLength {
00022                         get { return headers.headerCollection["Content-Length"]; }
00023                         set {
00024                                 try {
00025                                         string oldLength = "Content-Length: " + headers.headerCollection["Content-length"];
00026                                         string newLength = "Content-Length: " + value;
00027                                         headers.rawString.Replace(oldLength, newLength); 
00028                                 } catch (Exception ex) {
00029                                         Console.WriteLine("*** Error occured trying to set new Content Length value for response: {0} ***", ex.Message);
00030                                 }
00031                                 this.headers.parseRaw();
00032                         }
00033                 }
00034                 public string Headers {
00035                         get { return headers.rawString; }
00036                 }
00037 
00038                 public int StatusCode {
00039                         get { return Int32.Parse(((HTTPResponseHeader)headers).statusCode); }
00040                 }
00041 
00042                 public HTTPBody Body {
00043                         get { return body; }
00044                 }
00045                 /*** Constructors ***/
00046                 public HTTPResponse(HTTPResponseHeader headers) {
00047                         this.headers = headers;
00048                 }
00049 
00050                 public HTTPResponse(ref Stream nwstream) {
00051                         StringBuilder sb = new StringBuilder();
00052                         string s1 = StreamUtil.ReadLine(ref nwstream);                  
00053                         while (s1 != "") { // the blank line is a marker
00054                                 sb.Append(s1 + "\r\n");
00055                                 s1 = StreamUtil.ReadLine(ref nwstream);
00056                         } 
00057                         sb.Append("\r\n");
00058                         // parse the response and see what kind of message it was
00059                         this.headers = new HTTPResponseHeader(sb.ToString());
00060                         // if we have data to receive, we can receive "Content-length" number of bits!
00061                         if (this.headers.headerCollection["Content-Length"] != null) {
00062                                 int bodySize = Int32.Parse(this.headers.headerCollection["Content-Length"]);
00063                                 byte[] bodyBuffer = StreamUtil.ReadBody(ref nwstream, bodySize);
00064                                 this.body = new HTTPBody(bodyBuffer);
00065                         } // otherwise, we could be in a case where connection is terminating determines size
00066                         else if ((this.headers.headerCollection["Connection"] == "Close") || ((HTTPResponseHeader)this.headers).statusCode == "200") {
00067                                 // TODO: find more conditions for having a body
00068                                 try {
00069                                         byte[] bodyBuffer = StreamUtil.ReadBody(ref nwstream);
00070                                         this.body = new HTTPBody(bodyBuffer);
00071                                 } catch (Exception ex) {
00072                                         // TODO: better exception handling here,and all round
00073                                         Console.WriteLine(ex);
00074                                 }
00075                         }
00076                 }
00077 
00078                 public HTTPResponse() {}
00079 
00080                 public HTTPResponse(byte[] src) : base(src) {
00081                         if (headerBytes != null) {
00082                                 headers = new HTTPResponseHeader(headerBytes);
00083                         }
00084                         if (bodyBytes != null) {
00085                                 body = new HTTPBody(bodyBytes);
00086                         }
00087                 }
00088         }
00089 
00090         /**************************************************************************************************/
00091         public class HTTPResponseHeader : HTTPHeader {
00092                 // deals differently with HTTP nnn xxxxxx header
00093                 public string statusCode;
00094                 /*** Constructors ***/
00095                 public HTTPResponseHeader(string source) : base(source) {}
00096                 public HTTPResponseHeader(byte[] src) : base(Encoding.ASCII.GetString(src)) {}
00097 
00098                 /*** Methods ***/
00099                 protected override void parseHTTP() {
00100                         int i1 = rawStringPos;
00101                         int i2 = rawString.IndexOf("\r\n");
00102                         int i3;
00103                         string s = rawString.Substring(i1,i2-i1);
00104                         // do parsing work
00105                         // extract HTML version
00106                         i3 = s.IndexOf(' ');
00107                         //                      this.parseVersionInfo(s.Substring(i1, i3-i1));
00108                         i1 = i3 + 1;
00109                         // extract status code
00110                         i3 = s.IndexOf(' ', i1);
00111                         this.parseStatusCode(s.Substring(i1, i3-i1));
00112                         rawStringPos = i2 + "\r\n".Length;
00113                 }
00114 
00115                 protected void parseStatusCode(string src) {
00116                         statusCode = src;       
00117                 }
00118         }
00119         /**************************************************************************************************/
00120         public class HTTPResponseQueueObject : HTTPResponse {
00121                 public ushort destinationDeviceID;
00122                 // additional property 1
00123                 // additional property 2
00124 
00125                 public HTTPResponseQueueObject() : base() {             }
00126                 public HTTPResponseQueueObject(ref Stream nwstream) : base(ref nwstream) {}
00127                 public HTTPResponseQueueObject(HTTPResponseHeader headers) : base(headers) {}
00128         
00129         }
00130         /**************************************************************************************************/
00134         public class EncodedHTTPResponse : EncodedData {
00135                 byte[] compressedData;
00136                 bool isDeltaEncoded;
00141                 public EncodedHTTPResponse(HTTPResponse response) : this(response, null, null) {}
00142 
00149                 public EncodedHTTPResponse(HTTPResponse resp, byte[] originalCHk, CacheManager cacheManager) {
00150                         MemoryStream uncompressedDataStream = new MemoryStream();
00151                         if (originalCHk != null && cacheManager != null && resp.ContentType.StartsWith("text")) { // then delta encode
00152                                 byte[] oldBodyBytes = cacheManager.GetByChk(originalCHk).data;
00153                                 if (Math.Abs(oldBodyBytes.Length - resp.Body.data.Length) <= (16 * 1024)) {
00154                                         isDeltaEncoded = true;
00155                                         MemoryStream oldBodyData = new MemoryStream(oldBodyBytes);
00156                                         MemoryStream newBodyData = new MemoryStream(resp.Body.data);
00157                                         ArrayList changeHunks = CacheManager.Diff(oldBodyData, newBodyData);
00158                                         // serialise the change hunks
00159                                         IFormatter formatter = new BinaryFormatter();
00160 
00161                                         resp.AppendBody(null); // cancel out the body of this response
00162                                         byte[] serilaisedHeaders = resp.Serialise();
00163 
00164                                         // start to write the uncompressed data stream
00165                                         uncompressedDataStream.Write(BitConverter.GetBytes(serilaisedHeaders.Length), 0, BitConverter.GetBytes(serilaisedHeaders.Length).Length);
00166                                         uncompressedDataStream.Write(serilaisedHeaders, 0, serilaisedHeaders.Length);
00167                                         uncompressedDataStream.Write(originalCHk, 0, originalCHk.Length);
00168                                         formatter.Serialize(uncompressedDataStream, changeHunks);
00169                                 } else { // too much difference to delta encode?
00170                                         isDeltaEncoded = false;
00171                                         byte[] serialisedResponse = resp.Serialise();
00172                                         uncompressedDataStream.Write(serialisedResponse, 0, serialisedResponse.Length);
00173                                 }
00174                         } else {
00175                                 isDeltaEncoded = false;
00176                                 byte[] serialisedResponse = resp.Serialise();
00177                                 uncompressedDataStream.Write(serialisedResponse, 0, serialisedResponse.Length);
00178                         }
00179                         // even if it IS delata encoded, zip the encoded stuff.
00180                         compressedData = Zip(uncompressedDataStream);
00181                         uncompressedDataStream.Close();
00182                         // the IS delta Encoded bit will be written before the compressed data
00183                 }
00184 
00191                 public EncodedHTTPResponse(byte[] src, int start, int length) {
00192                         Deserialise(src, start, length);
00193                 }
00194 
00195                 public byte[] Serialise() {
00196                         MemoryStream buffer = new MemoryStream();
00197                         buffer.Write(BitConverter.GetBytes(isDeltaEncoded), 0, BitConverter.GetBytes(isDeltaEncoded).Length);
00198                         buffer.Write(compressedData, 0, compressedData.Length);
00199                         byte[] result = new byte[buffer.Length];
00200                         buffer.Seek(0, SeekOrigin.Begin);
00201                         buffer.Read(result, 0, result.Length);
00202                         buffer.Close();
00203                         return result;
00204                 }
00205 
00206                 public void Deserialise(byte[] src, int start, int length) {
00207                         int currentPos = start;
00208                         isDeltaEncoded = BitConverter.ToBoolean(src, currentPos);
00209                         currentPos += 1;
00210                         compressedData = new byte[(length - currentPos) + start];
00211                         Array.Copy(src, currentPos, compressedData, 0, compressedData.Length);
00212                 }
00213 
00214 
00220                 public HTTPResponse Decode(CacheManager cacheManager) {
00221                         MemoryStream compressedDataStream = new MemoryStream(compressedData);
00222                         HTTPResponse result;
00223                         if (isDeltaEncoded) {
00224                                 byte[] uncompressedData = Unzip(ref compressedDataStream);
00225                                 int currentPos = 0;
00226                                 // get headers
00227                                 int headerLength = BitConverter.ToInt32(uncompressedData, currentPos);
00228                                 currentPos += 4;
00229                                 byte[] headerBytes = new byte[headerLength];
00230                                 Array.Copy(uncompressedData, currentPos, headerBytes, 0, headerLength);
00231                                 currentPos += headerLength;
00232                                 // start HTTPResponse creation
00233                                 result = new HTTPResponse(headerBytes);
00234                                 // get original chk
00235                                 byte[] originalChk = new byte[20];
00236                                 Array.Copy(uncompressedData, currentPos, originalChk, 0, originalChk.Length);
00237                                 currentPos += 20;
00238                                 // get hunk list
00239                                 MemoryStream partialUncompressedStream = new MemoryStream(uncompressedData, currentPos, uncompressedData.Length - currentPos);
00240                                 IFormatter formatter = new BinaryFormatter();
00241                                 ArrayList hunkList = (ArrayList) formatter.Deserialize(partialUncompressedStream);
00242                                 /*************** WHAT HAPPENS IF DOCUMENT NOT IN CACHE WHEN WE TRY AND FETCH IT ***********/
00243                                 /**************** THROW EXCEPTION UPWARDS AND RE-ISSUE AT CALLER */
00244                                 HTTPBody oldDocBody = cacheManager.GetByChk(originalChk);
00245                                 byte[] newDocBytes = CacheManager.Patch(oldDocBody.data, hunkList);
00246                                 result.AppendBody(new HTTPBody(newDocBytes));
00247                         } else {
00248                                 result = new HTTPResponse(Unzip(ref compressedDataStream));
00249                         }
00250                         compressedDataStream.Close();
00251                         return result;
00252                 }
00253                 /*
00254                  *                      MemoryStream baseInflationStream = new MemoryStream(compressedData);
00255                         MemoryStream deflatedOutput = new MemoryStream();
00256                         byte[] buffer = new byte[512];
00257                         int bytesRead;
00258                         InflaterInputStream inflateStream = new InflaterInputStream(baseInflationStream);
00259                         bytesRead = inflateStream.Read(buffer, 0, buffer.Length);
00260                         while (bytesRead > 0) {
00261                                 deflatedOutput.Write(buffer, 0, bytesRead);
00262                                 bytesRead = inflateStream.Read(buffer, 0, buffer.Length);
00263                         }
00264                         inflateStream.Flush();
00265                         inflateStream.Close();
00266                         deflatedOutput.Flush();
00267                         HTTPResponse result = new HTTPResponse(deflatedOutput.GetBuffer());
00268                         deflatedOutput.Close();
00269                         return result;
00270                         */
00271 
00272 
00273         }
00274 
00275         public class EncodedData {
00279                 protected byte[] Unzip(ref MemoryStream compressedStream) {
00280                         MemoryStream deflatedOutput = new MemoryStream();
00281                         byte[] buffer = new byte[512];
00282                         int bytesRead;
00283                         InflaterInputStream inflateStream = new InflaterInputStream(compressedStream);
00284                         bytesRead = inflateStream.Read(buffer, 0, buffer.Length);
00285                         while (bytesRead > 0) {
00286                                 deflatedOutput.Write(buffer, 0, bytesRead);
00287                                 bytesRead = inflateStream.Read(buffer, 0, buffer.Length);
00288                         }
00289                         inflateStream.Flush();
00290                         inflateStream.Close();
00291                         deflatedOutput.Flush();
00292                         byte[] result = new byte[deflatedOutput.Length];
00293                         deflatedOutput.Seek(0, SeekOrigin.Begin);
00294                         deflatedOutput.Read(result, 0, result.Length);
00295                         deflatedOutput.Close();
00296                         return result;
00297                 }
00298 
00299                 protected byte[] Zip(MemoryStream uncompressedDataStream) {
00300                         MemoryStream compressedDataStream = new MemoryStream();
00301                         DeflaterOutputStream deflaterStream = new DeflaterOutputStream(compressedDataStream);
00302                         uncompressedDataStream.WriteTo(deflaterStream);
00303                         deflaterStream.Flush();
00304                         deflaterStream.Finish();
00305                         byte[] result = new byte[compressedDataStream.Length];
00306                         compressedDataStream.Seek(0, SeekOrigin.Begin);
00307                         compressedDataStream.Read(result, 0, result.Length);
00308                         deflaterStream.Close();
00309                         compressedDataStream.Close();
00310                         return result;
00311                 }
00312 
00313                 public static byte[] StaticUnzip(ref MemoryStream compressedStream) {
00314                         EncodedData instance = new EncodedData();
00315                         return instance.Unzip(ref compressedStream);
00316                 }
00317 
00318                 public static byte[] StaticZip(MemoryStream uncompressedDataStream) {
00319                         EncodedData instance = new EncodedData();
00320                         return instance.Zip(uncompressedDataStream);
00321                 }
00322         }
00323 }
00324 

Generated on Mon May 8 22:07:27 2006 by  doxygen 1.3.9.1