/// <summary> /// Begin writing to a network stream /// </summary> private Task WriteAsync <T, U>(PipeTaskState <T> state, PipeRequest <U> request, CancellationToken cancellationToken) { try { if (cancellationToken.IsCancellationRequested) { cancellationToken.ThrowIfCancellationRequested(); } if (!_pipeClient.IsConnected) { throw new IOException("Unable to send message, no connection established."); } if (_pipeClient.CanWrite) { return(_pipeClient.WriteAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request)), cancellationToken).AsTask()); } } catch (Exception ex) { _logger.Error($"{nameof(WriteAsync)}-{ex.Message}"); state.Response = PipeResponse <T> .SetFail(ex.Message); } return(Task.CompletedTask); }
/// <summary> /// Begin reading from a network stream /// </summary> private Task ReadAsync <T>(PipeTaskState <T> state, CancellationToken cancellationToken) { if (state.Response != null && state.Response.IsSuccess == false) { return(Task.CompletedTask); } try { if (cancellationToken.IsCancellationRequested) { cancellationToken.ThrowIfCancellationRequested(); } if (!_pipeClient.IsConnected) { throw new IOException("Unable to recieve message, no connection established."); } if (_pipeClient.CanRead) { return(_pipeClient.ReadAsync(_memoryOwner.Memory, cancellationToken).AsTask()); } } catch (Exception ex) { _logger.Error($"{nameof(ReadAsync)}-{ex.Message}"); state.Response = PipeResponse <T> .SetFail(ex.Message); } return(Task.CompletedTask); }
/// <summary> /// <see cref="PipeResponse"/> から <see cref="HttpResponseMessage"/> を作成します。 /// </summary> /// <param name="pipeResponse"><see cref="HttpResponseMessage"/> を作成するための <see cref="PipeResponse"/></param> /// <param name="request"><see cref="HttpResponseMessage"/> を作成するための <see cref="HttpRequestMessage"/></param> /// <param name="checkAction">カスタムで処理を行う場合のアクション</param> /// <remarks> /// デフォルトで以下の判定を行います。 /// <list type="list"> /// <item><see cref="PipeResponse.Data"/>が<see cref="null"/>の場合は、HTTPステータスコード Not Found の <see cref="HttpResponseMessage"/>を返します。</item> /// <item>結果が<see cref="ValidationResult"/>で<see cref="ValidationResult.IsValid"/>が <see cref="false"/> の場合は、 HTTPステータスコード で BadRequest を返します。</item> /// <item>上記以外の場合は<see cref="HttpResponseMessage" /> に <see cref="PipeResponse.StatusCode"/> と、<see cref="PipeResponse.Data"/>の値を設定してかえします。</item> /// </list> /// </remarks> /// <returns><see cref="HttpResponseMessage"/></returns> public static HttpResponseMessage CreateHttpResponse(this PipeResponse pipeResponse, HttpRequestMessage request, Func <PipeResponse, Func <HttpResponseMessage>, HttpResponseMessage> checkAction = null) { Contract.NotNull(pipeResponse, "pipeResponse"); Contract.NotNull(request, "request"); var defaultAction = new DefaultResponseAction(request, pipeResponse); if (checkAction != null) { return(checkAction(pipeResponse, defaultAction.CreateHttpResponse)); } return(defaultAction.CreateHttpResponse()); }
/// <summary> /// Wait for a pipe to drain before another write/read /// </summary> private void WaitForPipeDrain <T>(PipeTaskState <T> state) { try { _pipeClient.WaitForPipeDrain(); } catch (Exception ex) { _logger.Error(ex.Message); state.Response = PipeResponse <T> .SetFail(ex.Message); } }
/// <summary> /// Convert response from /// </summary> private void ConvertResponse <T>(PipeTaskState <T> state) { if (state.Response != null && state.Response.IsSuccess == false) { return; } try { var json = Encoding.UTF8.GetString(_memoryOwner.Memory.Span).TrimEnd('\0'); if (string.IsNullOrWhiteSpace(json)) { throw new IOException("Response from server is empty."); } state.Response = JsonConvert.DeserializeObject <PipeResponse <T> >(json); } catch (Exception ex) { _logger.Error($"{nameof(ReadAsync)}-{ex.Message}"); state.Response = PipeResponse <T> .SetFail(ex.Message); } }
public DefaultResponseAction(HttpRequestMessage request, PipeResponse pipeResponse) { this.request = request; this.pipeResponse = pipeResponse; }
public static IDisposable Create(AppDelegate app, int port, string path) { app = ErrorPage.Middleware(app); var effectivePath = path ?? ""; if (!effectivePath.EndsWith("/")) effectivePath += "/"; var listener = new System.Net.HttpListener(); listener.Prefixes.Add(string.Format("http://+:{0}{1}", port, effectivePath)); listener.Start(); Action go = () => { }; go = () => listener.BeginGetContext( ar => { HttpListenerContext context; try { context = listener.EndGetContext(ar); } finally { // ReSharper disable AccessToModifiedClosure go(); // ReSharper restore AccessToModifiedClosure } var requestPathBase = effectivePath; if (requestPathBase == "/" || requestPathBase == null) requestPathBase = ""; var requestPath = context.Request.Url.AbsolutePath; if (string.IsNullOrEmpty(requestPath)) requestPath = "/"; if (requestPath.StartsWith(requestPathBase, StringComparison.OrdinalIgnoreCase)) requestPath = requestPath.Substring(requestPathBase.Length); var requestQueryString = context.Request.Url.GetComponents(UriComponents.Query, UriFormat.UriEscaped); var requestHeaders = context.Request.Headers.AllKeys .ToDictionary(x => x, x => (IEnumerable<string>)context.Request.Headers.GetValues(x), StringComparer.OrdinalIgnoreCase); var env = new Dictionary<string, object> { {OwinConstants.Version, "1.0"}, {OwinConstants.RequestMethod, context.Request.HttpMethod}, {OwinConstants.RequestScheme, context.Request.Url.Scheme}, {OwinConstants.RequestPathBase, requestPathBase}, {OwinConstants.RequestPath, requestPath}, {OwinConstants.RequestQueryString, requestQueryString}, {OwinConstants.RequestHeaders, requestHeaders}, {OwinConstants.RequestBody, RequestBody(context.Request.InputStream)}, {"System.Net.HttpListenerContext", context}, {"server.CLIENT_IP", context.Request.RemoteEndPoint.Address.ToString()}, }; app(env, (status, headers, body) => { context.Response.StatusCode = int.Parse(status.Substring(0, 3)); context.Response.StatusDescription = status.Substring(4); foreach (var kv in headers) { // these may not be assigned via header collection if (string.Equals(kv.Key, "Content-Length", StringComparison.OrdinalIgnoreCase)) { context.Response.ContentLength64 = long.Parse(kv.Value.Single()); } else if (string.Equals(kv.Key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) { context.Response.KeepAlive = true; } //else if (string.Equals(kv.Key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) //{ // // not sure what can be done about this //} //else if (string.Equals(kv.Key, "WWW-Authenticate", StringComparison.OrdinalIgnoreCase)) //{ // // not sure what httplistener properties to assign //} else { // all others are foreach (var v in kv.Value) { context.Response.Headers.Add(kv.Key, v); } } } var pipeResponse = new PipeResponse( context.Response.OutputStream, ex => context.Response.Close(), () => context.Response.Close()); pipeResponse.Go(body); }, ex => { // This should never be called throw new NotImplementedException(); }); }, null); go(); return new Disposable(() => { go = () => { }; listener.Stop(); }); }