public void UnsupportedHttpMethodReturnsMethodNotAllowed() { A.CallTo(() => this.request.HttpMethod).Returns(HttpMethod.Get); ISydneyResponse response = this.handler.HandleRequestAsync( this.request, this.logger, false).Result; Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode); }
public void UnexpectedExceptionFromHandlerMethodReturnsInternalServerError() { A.CallTo(this.handler) .Where(call => call.Method.Name == "GetAsync") .Throws(new InvalidOperationException()); A.CallTo(() => this.request.HttpMethod).Returns(HttpMethod.Get); ISydneyResponse response = this.handler.HandleRequestAsync( this.request, this.logger, false).Result; Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); }
public void HttpResponseExceptionFromHandlerMethodReturnsSpecifiedStatusCode() { A.CallTo(this.handler) .Where(call => call.Method.Name == "GetAsync") .Throws(new HttpResponseException(HttpStatusCode.EarlyHints)); A.CallTo(() => this.request.HttpMethod).Returns(HttpMethod.Get); ISydneyResponse response = this.handler.HandleRequestAsync( this.request, this.logger, false).Result; Assert.Equal(HttpStatusCode.EarlyHints, response.StatusCode); }
public void ExceptionMessageIsReturnedInPayloadWhenReturnExceptionMessagesInResponseIsTrue() { string expectedExceptionMessage = "Here's an exception!"; A.CallTo(this.handler) .Where(call => call.Method.Name == "GetAsync") .Throws(new InvalidOperationException(expectedExceptionMessage)); A.CallTo(() => this.request.HttpMethod).Returns(HttpMethod.Get); ISydneyResponse response = this.handler.HandleRequestAsync( this.request, this.logger, true).Result; Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedExceptionMessage, response.Payload); }
public void HttpMethodMapsToCorrectHandlerMethodAsync(HttpMethod httpMethod, string handlerMethodName) { A.CallTo(this.handler) .Where(call => call.Method.Name == handlerMethodName) .WithReturnType <Task <ISydneyResponse> >() .Returns(Task.FromResult <ISydneyResponse>(new SydneyResponse(HttpStatusCode.Ambiguous))); A.CallTo(() => this.request.HttpMethod).Returns(httpMethod); ISydneyResponse response = this.handler.HandleRequestAsync( this.request, this.logger, false).Result; Assert.Equal(HttpStatusCode.Ambiguous, response.StatusCode); A.CallTo(this.handler) .Where(call => call.Method.Name == handlerMethodName) .MustHaveHappenedOnceExactly(); }
internal async Task <ISydneyResponse> HandleRequestAsync(ISydneyRequest request, ILogger logger, bool returnExceptionMessagesInResponse) { Stopwatch stopwatch = Stopwatch.StartNew(); try { ISydneyResponse response = null; switch (request.HttpMethod) { case HttpMethod.Get: response = await this.GetAsync(request); break; case HttpMethod.Post: response = await this.PostAsync(request); break; case HttpMethod.Delete: response = await this.DeleteAsync(request); break; case HttpMethod.Put: response = await this.PutAsync(request); break; case HttpMethod.Head: response = await this.HeadAsync(request); break; case HttpMethod.Patch: response = await this.PatchAsync(request); break; case HttpMethod.Options: response = await this.OptionsAsync(request); break; default: throw new NotImplementedException(); } logger.LogInformation($"Request completed after {stopwatch.Elapsed}, status code: {response.StatusCode}."); return(response); } catch (Exception exception) { HttpStatusCode statusCode = HttpStatusCode.InternalServerError; switch (exception) { case HttpResponseException hre: logger.LogWarning( hre, $"Request failed after {stopwatch.Elapsed}, status code: {hre.StatusCode}, exception: {hre}"); statusCode = hre.StatusCode; break; case NotImplementedException nie: logger.LogWarning( nie, $"Request made for unsupported HTTP method {request.HttpMethod}."); statusCode = HttpStatusCode.MethodNotAllowed; break; default: logger.LogError( exception, $"Unexpected exception processing request after {stopwatch.Elapsed}, exception: {exception}"); break; } return (new SydneyResponse( statusCode, returnExceptionMessagesInResponse ? exception.Message : null)); } }
internal async Task HandleContextAsync(HttpListenerContext context) { try { // Try to match the incoming URL to a handler. if (!this.router.TryMatchPath(context.Request.Url.AbsolutePath, out RouteMatch match)) { this.logger.LogWarning($"No matching handler found for incoming request url: {context.Request.Url}."); // If we couldn't, return a 404. context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.Close(); return; } // Create and handle the request. ISydneyRequest request = new SydneyRequest(context.Request, match.PathParameters); ISydneyResponse response = await match.Handler.HandleRequestAsync( request, this.logger, this.config.ReturnExceptionMessagesInResponse); // Write the response to context.Response. context.Response.StatusCode = (int)response.StatusCode; context.Response.KeepAlive = response.KeepAlive; foreach (KeyValuePair <string, string> header in response.Headers) { context.Response.AddHeader(header.Key, header.Value); } if (response.Payload != null) { context.Response.ContentType = MediaTypeNames.Application.Json; // We have to serialize to a memory stream first in order to get the content length // because the output stream does not support the property. It seems good to initialize the // stream with a buffer size. 512 bytes was randomly chosen as a decent medium size for now. using (var memoryStream = new MemoryStream(DefaultBufferSize)) { await JsonSerializer.SerializeAsync(memoryStream, response.Payload); context.Response.ContentLength64 = memoryStream.Length; // Stream.CopyToAsync starts from the current position so seek to the beginning. memoryStream.Seek(0, SeekOrigin.Begin); await memoryStream.CopyToAsync(context.Response.OutputStream); } } else { context.Response.ContentLength64 = 0; } // Close the response to send it back to the client. context.Response.Close(); } catch (Exception exception) { this.logger.LogError( exception, $"Unexpected exception handling context, exception: {exception}"); // Forcefully end the connection. context.Response.Abort(); } }