/// <summary>
        /// Completes an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public void OnGetRequestStreamComplete(IAsyncResult result)
        {
            AsyncResult result2 = result.AsyncState as AsyncResult;

            if (result2 == null)
            {
                return;
            }

            try
            {
                Stream ostrm = result2.WebRequest.EndGetRequestStream(result);

                MemoryStream mstrm = new MemoryStream();

                if (m_settings.Configuration.UseBinaryEncoding)
                {
                    BinaryEncoder encoder = new BinaryEncoder(mstrm, this.MessageContext);
                    encoder.EncodeMessage(result2.Request);
                }
                else
                {
                    WriteSoapMessage(
                        mstrm, 
                        result2.Request.GetType().Name,
                        result2.Request,
                        this.MessageContext);
                }

                int bytesToRead = (int)mstrm.Position;
                mstrm.Position = 0;

                int bytesRead = 0;
                int blockSize = 0;
                byte[] buffer = new byte[4096];

                do
                {
                    blockSize = mstrm.Read(buffer, 0, buffer.Length);
                    bytesRead += blockSize;

                    if (bytesRead > bytesToRead)
                    {
                        blockSize -= (bytesRead - bytesToRead);
                    }

                    ostrm.Write(buffer, 0, blockSize);
                }
                while (blockSize >= 0 && bytesRead < bytesToRead);

                ostrm.Close();

                result2.InnerResult = result2.WebRequest.BeginGetResponse(OnBeginGetResponseComplete, result2);
            }
            catch (Exception exception)
            {
                result2.Exception = exception;
                result2.OperationCompleted();
            }
        }
Ejemplo n.º 2
0
        private Stream EndProcessRequest(IAsyncResult result)
        {
            MemoryStream ostrm = new MemoryStream();

            try
            {
                if (m_callback != null)
                {
                    IServiceResponse response = m_callback.EndProcessRequest(result);

                    string contentType = WebOperationContext.Current.IncomingRequest.ContentType;

                    if (contentType == "application/octet-stream")
                    {
                        BinaryEncoder encoder = new BinaryEncoder(ostrm, this.m_quotas.MessageContext);
                        encoder.EncodeMessage(response);
                    }
                    else
                    {
                        HttpsTransportChannel.WriteSoapMessage(
                            ostrm,
                            response.GetType().Name,
                            response,
                            this.m_quotas.MessageContext);
                    }

                    ostrm.Position = 0;
                }
            }
            catch (Exception e)
            {
                Utils.Trace(e, "TCPLISTENER - Unexpected error sending result.");
            }

            return ostrm;
        }
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        public async Task SendAsync(HttpContext context)
        {
            IAsyncResult result = null;

            try
            {
                if (m_callback == null)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.NotImplemented;
                    await context.Response.WriteAsync(string.Empty).ConfigureAwait(false);

                    return;
                }

                if (context.Request.ContentType != "application/octet-stream")
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Unsupported content type.").ConfigureAwait(false);

                    return;
                }

                int    length = (int)context.Request.ContentLength;
                byte[] buffer = await ReadBodyAsync(context.Request).ConfigureAwait(false);

                if (buffer.Length != length)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Couldn't decode buffer.").ConfigureAwait(false);

                    return;
                }

                IServiceRequest input = (IServiceRequest)BinaryDecoder.DecodeMessage(buffer, null, m_quotas.MessageContext);

                // extract the JWT token from the HTTP headers.
                if (input.RequestHeader == null)
                {
                    input.RequestHeader = new RequestHeader();
                }

                if (NodeId.IsNull(input.RequestHeader.AuthenticationToken) && input.TypeId != DataTypeIds.CreateSessionRequest)
                {
                    if (context.Request.Headers.Keys.Contains("Authorization"))
                    {
                        foreach (string value in context.Request.Headers["Authorization"])
                        {
                            if (value.StartsWith("Bearer"))
                            {
                                input.RequestHeader.AuthenticationToken = new NodeId(value.Substring("Bearer ".Length).Trim());
                            }
                        }
                    }
                }

                EndpointDescription endpoint = null;

                foreach (var ep in m_descriptions)
                {
                    if (ep.EndpointUrl.StartsWith(Utils.UriSchemeHttps))
                    {
                        endpoint = ep;
                        break;
                    }
                }

                result = m_callback.BeginProcessRequest(
                    m_listenerId,
                    endpoint,
                    input as IServiceRequest,
                    null,
                    null);

                IServiceResponse output = m_callback.EndProcessRequest(result);

                byte[] response = BinaryEncoder.EncodeMessage(output, m_quotas.MessageContext);
                context.Response.ContentLength = response.Length;
                context.Response.ContentType   = context.Request.ContentType;
                context.Response.StatusCode    = (int)HttpStatusCode.OK;
#if NETSTANDARD2_1
                await context.Response.Body.WriteAsync(response.AsMemory(0, response.Length)).ConfigureAwait(false);
#else
                await context.Response.Body.WriteAsync(response, 0, response.Length).ConfigureAwait(false);
#endif
            }
            catch (Exception e)
            {
                Utils.Trace(e, "HTTPSLISTENER - Unexpected error processing request.");
                context.Response.ContentLength = e.Message.Length;
                context.Response.ContentType   = "text/plain";
                context.Response.StatusCode    = (int)HttpStatusCode.InternalServerError;
                await context.Response.WriteAsync(e.Message).ConfigureAwait(false);
            }
        }
        /// <summary>
        /// Secures the message using the security token.
        /// </summary>
        protected BufferCollection WriteSymmetricMessage(
            uint messageType,
            uint requestId,
            ChannelToken token,
            object messageBody,
            bool isRequest,
            out bool limitsExceeded)
        {
            limitsExceeded = false;
            bool             success         = false;
            BufferCollection chunksToProcess = null;

            try
            {
                // calculate chunk sizes.
                int maxCipherTextSize = SendBufferSize - TcpMessageLimits.SymmetricHeaderSize;
                int maxCipherBlocks   = maxCipherTextSize / EncryptionBlockSize;
                int maxPlainTextSize  = maxCipherBlocks * EncryptionBlockSize;
                int maxPayloadSize    = maxPlainTextSize - SymmetricSignatureSize - 1 - TcpMessageLimits.SequenceHeaderSize;
                int headerSize        = TcpMessageLimits.SymmetricHeaderSize + TcpMessageLimits.SequenceHeaderSize;

                // write the body to stream.
                ArraySegmentStream ostrm = new ArraySegmentStream(
                    BufferManager,
                    SendBufferSize,
                    headerSize,
                    maxPayloadSize);

                // check for encodeable body.
                IEncodeable encodeable = messageBody as IEncodeable;

                if (encodeable != null)
                {
                    // debug code used to verify that message aborts are handled correctly.
                    // int maxMessageSize = Quotas.MessageContext.MaxMessageSize;
                    // Quotas.MessageContext.MaxMessageSize = Int32.MaxValue;

                    BinaryEncoder.EncodeMessage(encodeable, ostrm, Quotas.MessageContext);

                    // Quotas.MessageContext.MaxMessageSize = maxMessageSize;
                }

                // check for raw bytes.
                ArraySegment <byte>?rawBytes = messageBody as ArraySegment <byte>?;

                if (rawBytes != null)
                {
                    BinaryEncoder encoder = new BinaryEncoder(ostrm, Quotas.MessageContext);
                    encoder.WriteRawBytes(rawBytes.Value.Array, rawBytes.Value.Offset, rawBytes.Value.Count);
                    encoder.Close();
                }

                chunksToProcess = ostrm.GetBuffers("WriteSymmetricMessage");

                // ensure there is at least one chunk.
                if (chunksToProcess.Count == 0)
                {
                    byte[] buffer = BufferManager.TakeBuffer(SendBufferSize, "WriteSymmetricMessage");
                    chunksToProcess.Add(new ArraySegment <byte>(buffer, 0, 0));
                }

                BufferCollection chunksToSend = new BufferCollection(chunksToProcess.Capacity);

                int messageSize = 0;

                for (int ii = 0; ii < chunksToProcess.Count; ii++)
                {
                    ArraySegment <byte> chunkToProcess = chunksToProcess[ii];

                    // nothing more to do if limits exceeded.
                    if (limitsExceeded)
                    {
                        BufferManager.ReturnBuffer(chunkToProcess.Array, "WriteSymmetricMessage");
                        continue;
                    }

                    MemoryStream  strm    = new MemoryStream(chunkToProcess.Array, 0, SendBufferSize);
                    BinaryEncoder encoder = new BinaryEncoder(strm, Quotas.MessageContext);

                    // check if the message needs to be aborted.
                    if (MessageLimitsExceeded(isRequest, messageSize + chunkToProcess.Count - headerSize, ii + 1))
                    {
                        encoder.WriteUInt32(null, messageType | TcpMessageType.Abort);

                        // replace the body in the chunk with an error message.
                        BinaryEncoder errorEncoder = new BinaryEncoder(
                            chunkToProcess.Array,
                            chunkToProcess.Offset,
                            chunkToProcess.Count,
                            Quotas.MessageContext);

                        WriteErrorMessageBody(errorEncoder, (isRequest) ? StatusCodes.BadRequestTooLarge : StatusCodes.BadResponseTooLarge);

                        int size = errorEncoder.Close();
                        chunkToProcess = new ArraySegment <byte>(chunkToProcess.Array, chunkToProcess.Offset, size);

                        limitsExceeded = true;
                    }

                    // check if the message is complete.
                    else if (ii == chunksToProcess.Count - 1)
                    {
                        encoder.WriteUInt32(null, messageType | TcpMessageType.Final);
                    }

                    // more chunks to follow.
                    else
                    {
                        encoder.WriteUInt32(null, messageType | TcpMessageType.Intermediate);
                    }

                    int count = 0;

                    count += TcpMessageLimits.SequenceHeaderSize;
                    count += chunkToProcess.Count;
                    count += SymmetricSignatureSize;

                    // calculate the padding.
                    int padding = 0;

                    if (SecurityMode == MessageSecurityMode.SignAndEncrypt)
                    {
                        // reserve one byte for the padding size.
                        count++;

                        if (count % EncryptionBlockSize != 0)
                        {
                            padding = EncryptionBlockSize - (count % EncryptionBlockSize);
                        }

                        count += padding;
                    }

                    count += TcpMessageLimits.SymmetricHeaderSize;

                    encoder.WriteUInt32(null, (uint)count);
                    encoder.WriteUInt32(null, ChannelId);
                    encoder.WriteUInt32(null, token.TokenId);

                    uint sequenceNumber = GetNewSequenceNumber();
                    encoder.WriteUInt32(null, sequenceNumber);

                    encoder.WriteUInt32(null, requestId);

                    // skip body.
                    strm.Seek(chunkToProcess.Count, SeekOrigin.Current);

                    // update message size count.
                    messageSize += chunkToProcess.Count;

                    // write padding.
                    if (SecurityMode == MessageSecurityMode.SignAndEncrypt)
                    {
                        for (int jj = 0; jj <= padding; jj++)
                        {
                            encoder.WriteByte(null, (byte)padding);
                        }
                    }

                    if (SecurityMode != MessageSecurityMode.None)
                    {
                        // calculate and write signature.
                        byte[] signature = Sign(token, new ArraySegment <byte>(chunkToProcess.Array, 0, encoder.Position), isRequest);

                        if (signature != null)
                        {
                            encoder.WriteRawBytes(signature, 0, signature.Length);
                        }
                    }

                    if (SecurityMode == MessageSecurityMode.SignAndEncrypt)
                    {
                        // encrypt the data.
                        ArraySegment <byte> dataToEncrypt = new ArraySegment <byte>(chunkToProcess.Array, TcpMessageLimits.SymmetricHeaderSize, encoder.Position - TcpMessageLimits.SymmetricHeaderSize);
                        Encrypt(token, dataToEncrypt, isRequest);
                    }

                    // add the header into chunk.
                    chunksToSend.Add(new ArraySegment <byte>(chunkToProcess.Array, 0, encoder.Position));
                }

                // ensure the buffers don't get cleaned up on exit.
                success = true;
                return(chunksToSend);
            }
            finally
            {
                if (!success)
                {
                    if (chunksToProcess != null)
                    {
                        chunksToProcess.Release(BufferManager, "WriteSymmetricMessage");
                    }
                }
            }
        }
Ejemplo n.º 5
0
/// <summary>
/// Invokes the _NAME_ service.
/// </summary>
    public IAsyncResult Begin_NAME_(_NAME_Request request, AsyncCallback callback, object asyncState)
    {
        byte[] buffer = BinaryEncoder.EncodeMessage(request, CreateContext());
        return(Channel.BeginInvokeService(new InvokeServiceMessage(buffer), callback, asyncState));
    }