WsMtomParams ProcessMtomHeader(string mtomHeaderValue) { // Create the mtom header class WsMtomParams mtomHeader = new WsMtomParams(); // Parse Mtom Content-Type parameters string[] fields = mtomHeaderValue.Substring(18).Split(';'); int fieldsLen = fields.Length; for (int i = 0; i < fieldsLen; ++i) { string[] param = fields[i].Split('='); if (param.Length > 1) { switch (param[0].ToUpper()) { case "BOUNDARY": if (param[1].Length > 72) { throw new ArgumentException("Mime boundary element length exceeded.", "boundary"); } mtomHeader.boundary = param[1]; break; case "TYPE": mtomHeader.type = param[1]; break; case "START": mtomHeader.start = param[1]; break; case "START-INFO": mtomHeader.startInfo = param[1]; break; default: break; } } } // Check required Mtom fields if (mtomHeader.boundary == null || mtomHeader.type == null || mtomHeader.start == null) { throw new ArgumentException("Bad content-type http response header. ErrorCode: 404"); } return(mtomHeader); }
/// <summary> /// Send an Http request containing an mtom message to an endpoint and waits for a response. /// </summary> /// <param name="bodyParts">A reference to the WsMtomBodyParts collection used to generate a mime multipart message.</param> /// <param name="endpointAddress">A string containing the endpoint address of a service that will receive /// <param name="isOneway">True = don't wait for response, false means wait for a response.</param> /// <param name="isChuncked">If true true the message will be chunk encoded.</param> /// <returns> /// A DpwSoapResponse object containing a WsWsaHeader and an XmlReader or null if no response is received /// or parsing fails. /// </returns> public DpwsSoapResponse SendRequest(ref WsMtomBodyParts bodyParts, string endpointAddress, bool isOneWay, bool isChuncked) { WsMtomParams mtomParams = new WsMtomParams(); if (bodyParts.Boundary == null) { bodyParts.Boundary = Guid.NewGuid().ToString() + '-' + Guid.NewGuid().ToString().Substring(0, 33); } mtomParams.start = bodyParts.Start; mtomParams.boundary = bodyParts.Boundary; WsMtom mtom = new WsMtom(); byte[] message = mtom.CreateMessage(bodyParts); WsMessage response = SendRequest(message, endpointAddress, isOneWay, isChuncked, mtomParams); if (isOneWay) { return(null); } XmlReader reader; WsWsaHeader header; try { reader = WsSoapMessageParser.ParseSoapMessage(response.Message, out header); bodyParts = response.BodyParts; } catch { System.Ext.Console.Write("ParseSoapMessage failed."); return(null); } return(new DpwsSoapResponse(header, reader)); }
/// <summary> /// Send an Http request to an endpoint and waits for a response. /// </summary> /// <param name="soapMessage">A byte array containing the soap message to be sent.</param> /// <param name="remoteEndpoint">A sting containing the name of a remote listening endpoint.</param> /// <param name="isOneWay">A parameter used to specify if this is a one way transaction.</param> /// <param name="isChuncked">If true true the message will be chunk encoded.</param> /// <param name="mtomParams">If not null contains parameters required to fix up the http header for mime multipart.</param> /// <returns>WsMessage object containing the soap response returned from a service endpoint.</returns> internal WsMessage SendRequest(byte[] soapMessage, string remoteEndpoint, bool isOneWay, bool isChuncked, WsMtomParams mtomParams) { System.Ext.Console.Write("Executing Send Request"); HttpWebRequest request = HttpWebRequest.Create(remoteEndpoint) as HttpWebRequest; request.Timeout = RequestTimeout; request.ReadWriteTimeout = (ReceiveTimeout > SendTimeOut) ? ReceiveTimeout : SendTimeOut; // Post method request.Method = "POST"; // If the message is Mtom if (mtomParams != null) { request.Headers.Add("Mime-Version", "1.0"); request.ContentType = "Multipart/Related;boundary=" + mtomParams.boundary + ";type=\"application/xop+xml\";start=\"" + mtomParams.start + "\";start-info=\"application/soap+xml\""; request.Headers.Add("Content-Description", "WSDAPI MIME multipart"); } else { request.ContentType = "application/soap+xml; charset=utf-8"; } request.UserAgent = "MFWsAPI"; request.KeepAlive = !isOneWay; request.Headers.Add("Cache-Control", "no-cache"); request.Headers.Add("Pragma", "no-cache"); // Not chunked. We know the full length of the content and send in one chunk. if (!isChuncked) { request.ContentLength = soapMessage.Length; } else // Set chunked property or content length on request. { System.Ext.Console.Write("Not supported"); } // Now sending the message. GetRequestStream actually sends the headers. using (Stream reqStream = request.GetRequestStream()) { // Write soap message reqStream.Write(soapMessage, 0, soapMessage.Length); // Flush the stream and force a write reqStream.Flush(); // Reset the encoding flags m_mtomHeader = null; if (!isOneWay) { // Get response, check the fields HttpWebResponse resp = request.GetResponse() as HttpWebResponse; if (resp == null) { throw new WebException("No response was received on the HTTP channel", WebExceptionStatus.ReceiveFailure); } try { if (resp.ProtocolVersion != HttpVersion.Version11) { throw new IOException("Invalid http version in response line."); } if (resp.StatusCode != HttpStatusCode.OK && resp.StatusCode != HttpStatusCode.Accepted) { throw new IOException("Bad status code in response: " + resp.StatusCode); } if (resp.ContentLength > 0) { // Return the soap response. byte[] soapResponse = new byte[resp.ContentLength]; Stream respStream = resp.GetResponseStream(); // Now need to read all data. We read in the loop until resp.ContentLength or zero bytes read. // Zero bytes read means there was error on server and it did not send all data. int respLength = (int)resp.ContentLength; for (int totalBytesRead = 0; totalBytesRead < respLength;) { int bytesRead = respStream.Read(soapResponse, totalBytesRead, (int)resp.ContentLength - totalBytesRead); // If nothing is read - means server closed connection or timeout. In this case no retry. if (bytesRead == 0) { break; } // Adds number of bytes read on this iteration. totalBytesRead += bytesRead; } // If this is Mtom process the header if (resp.Headers[HttpKnownHeaderNames.ContentType].ToLower().IndexOf("multipart/related;") != -1) { m_mtomHeader = ProcessMtomHeader(resp.Headers[HttpKnownHeaderNames.ContentType]); } WsMessage message; if (m_mtomHeader != null) { message = new WsMessage(soapResponse, m_mtomHeader.boundary, m_mtomHeader.start); } else { message = new WsMessage(soapResponse); } return(message); } // // ContentLenght == 0 is OK // else if (resp.ContentLength < 0) { throw new ProtocolViolationException("Invalid http header, content length: " + resp.ContentLength); } } finally { if (resp != null) { resp.Dispose(); } } } } return(null); }
/// <summary> /// Verifies values of specific headers. /// </summary> /// <returns>True if parsing is successful</returns> private bool ProcessKnownHeaders() { HttpStatusCode errorCode = 0; string errorName = ""; // The HTTP methid should be GET or POST if (m_httpRequest.HttpMethod != "POST" && m_httpRequest.HttpMethod != "GET") { errorCode = HttpStatusCode.NotImplemented; } // HTTP version should be 1.1 if (m_httpRequest.ProtocolVersion != HttpVersion.Version11) { errorCode = HttpStatusCode.BadRequest; } if (m_httpRequest.ContentLength64 > WsHttpServiceHost.MaxReadPayload) { errorCode = HttpStatusCode.Forbidden; // 403 errorName = HttpKnownHeaderNames.ContentLength; } WebHeaderCollection webHeaders = (System.Net.WebHeaderCollection)m_httpRequest.Headers; string strChunked = webHeaders[HttpKnownHeaderNames.TransferEncoding]; if (strChunked != null) { if (strChunked == "chunked") { m_chunked = true; } else { errorCode = HttpStatusCode.NotFound; // 404 errorName = HttpKnownHeaderNames.TransferEncoding; } } string strContentType = m_httpRequest.ContentType; if (strContentType != null) { strContentType = strContentType.ToLower(); if (strContentType.IndexOf("multipart/related;") == 0) { // Create the mtom header class m_mtomHeader = new WsMtomParams(); // Parse Mtom Content-Type parameters string[] fields = strContentType.Substring(18).Split(';'); int fieldsLen = fields.Length; for (int i = 0; i < fieldsLen; ++i) { string[] param = fields[i].Split('='); if (param.Length > 1) { switch (param[0].ToUpper()) { case "BOUNDARY": if (param[1].Length > 72) { throw new ArgumentException("Mime boundary element length exceeded.", "boundary"); } m_mtomHeader.boundary = param[1]; break; case "TYPE": m_mtomHeader.type = param[1]; break; case "START": m_mtomHeader.start = param[1]; break; case "START-INFO": m_mtomHeader.startInfo = param[1]; break; default: break; } } } // Check required Mtom fields if (m_mtomHeader.boundary == null || m_mtomHeader.type == null || m_mtomHeader.start == null) { errorCode = HttpStatusCode.NotFound; errorName = HttpKnownHeaderNames.ContentType; } } else if (strContentType.IndexOf("application/soap+xml") != 0) { errorCode = HttpStatusCode.NotFound; errorName = HttpKnownHeaderNames.ContentType; } } string strMimeVersion = webHeaders["Mime-Version"]; if (strMimeVersion != null) { if (strMimeVersion != "1.0") { errorCode = HttpStatusCode.NotFound; errorName = "Mime-Version"; } } if (errorCode != 0) { SendError((int)errorCode, errorName); return(false); } return(true); }
/// <summary> /// Releases all resources used by the HttpProcess object. /// </summary> public void Dispose() { m_mtomHeader = null; m_httpResponse.Close(); GC.SuppressFinalize(this); }
/// <summary> /// Processes a message /// </summary> /// <param name="msg">The message being processed.</param> /// <param name="ctx">The context associated with the message.</param> /// <returns>The handling status for this operation.</returns> protected override ChainResult OnProcessOutputMessage(ref WsMessage msg, BindingContext ctx) { byte[] data = null; // if the body is a byte[] then it is already serialized (UDP stuff) if (msg == null || (msg.Body != null && msg.Body is byte[])) { return(ChainResult.Continue); } // Build response message using (XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { WsSoapMessageWriter smw = new WsSoapMessageWriter(ctx.Version); // Write start message up to body element content smw.WriteSoapMessageStart(xmlWriter, msg, ctx.Version.IncludeSoapHeaders); if (msg.Body != null && msg.Serializer != null) { DataContractSerializer ser = (DataContractSerializer)msg.Serializer; // Serialize the body element ser.WriteObject(xmlWriter, msg.Body); if (ser.BodyParts != null && ser.BodyParts.Count > 0) { msg.BodyParts = ser.BodyParts; } } // Write end message smw.WriteSoapMessageEnd(xmlWriter); data = xmlWriter.ToArray(); } WsMtomBodyParts bodyParts = msg.BodyParts; if (bodyParts != null) { DataContractSerializer reqDcs = (DataContractSerializer)msg.Serializer; bodyParts.Start = "<soap@soap>"; bodyParts.AddStart(reqDcs.CreateNewBodyPart(data, bodyParts.Start)); if (reqDcs.BodyParts.Count > 0) { bodyParts.Add(reqDcs.BodyParts[0]); } WsMtomParams mtomParams = new WsMtomParams(); if (bodyParts.Boundary == null) { bodyParts.Boundary = Guid.NewGuid().ToString() + '-' + Guid.NewGuid().ToString().Substring(0, 33); } mtomParams.start = bodyParts.Start; mtomParams.boundary = bodyParts.Boundary; msg.MtomPropeties = mtomParams; WsMtom mtom = new WsMtom(); data = mtom.CreateMessage(bodyParts); } msg.Body = data; return(ChainResult.Continue); }
/// <summary> /// Method used to send a soap request over http to a service endpoint. /// </summary> /// <param name="soapMessage">A byte array contining a soap request message.</param> /// <param name="endpointAddress">A string containing the endpoint address of a service that will receive /// the request. This must be a transport address in the format http://ip_address:port/service_address.</param> /// <param name="isOneway">True = don't wait for response, false means wait for a response.</param> /// <param name="isChuncked">If true true the message will be chunk encoded.</param> /// <param name="mtomParams">If not null contains parameters required to fix up the http header for mime multipart.</param> /// <returns>WsMessage object containing the soap response returned from a service endpoint.</returns> private WsMessage SendRequest(byte[] soapMessage, string endpointAddress, bool isOneway, bool isChuncked, WsMtomParams mtomParams) { if (soapMessage == null) { throw new ArgumentNullException("DpwsHttpClient.SendRequest - soapMessage must not be null."); } if (endpointAddress == null) { throw new ArgumentNullException("DpwsHttpClient.SendRequest - endpointAddress must not be null."); } // Send the request WsMessage response = m_httpClient.SendRequest(soapMessage, endpointAddress, isOneway, isChuncked, mtomParams); return(response); }