private static async Task RequestReceived(HttpContext ctx) { string header = "[Komodo.Server] " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " RequestReceived "; DateTime startTime = DateTime.Now; try { #region Base-Handlers if (ctx.Request.Method == HttpMethod.OPTIONS) { await OptionsHandler(ctx); return; } if (ctx.Request.Url.Elements == null || ctx.Request.Url.Elements.Length == 0) { ctx.Response.StatusCode = 200; ctx.Response.ContentType = "text/html; charset=utf-8"; await ctx.Response.Send(RootHtml()); return; } if (ctx.Request.Url.Elements != null && ctx.Request.Url.Elements.Length > 0) { if (ctx.Request.Url.Elements.Length == 1) { if (String.Compare(ctx.Request.Url.Elements[0].ToLower(), "favicon.ico") == 0) { ctx.Response.StatusCode = 200; await ctx.Response.Send(Common.ReadBinaryFile("Assets/favicon.ico")); return; } if (String.Compare(ctx.Request.Url.Elements[0].ToLower(), "robots.txt") == 0) { ctx.Response.StatusCode = 200; ctx.Response.ContentType = "text/plain"; await ctx.Response.Send("User-Agent: *\r\nDisallow:\r\n"); return; } if (String.Compare(ctx.Request.Url.Elements[0].ToLower(), "loopback") == 0) { ctx.Response.StatusCode = 200; await ctx.Response.Send(); return; } if (String.Compare(ctx.Request.Url.Elements[0].ToLower(), "version") == 0) { ctx.Response.StatusCode = 200; ctx.Response.ContentType = "text/plain"; await ctx.Response.Send(_Version); return; } } } #endregion #region Admin-API string apiKey = ctx.Request.RetrieveHeaderValue(_Settings.Server.HeaderApiKey); if (ctx.Request.Url.Elements != null && ctx.Request.Url.Elements.Length > 0 && ctx.Request.Url.Elements[0].Equals("admin")) { if (String.IsNullOrEmpty(apiKey)) { _Logging.Warn(header + "admin API requested but no API key specified"); ctx.Response.StatusCode = 401; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(401, "No API key specified.", null, null).ToJson(true)); return; } if (String.Compare(_Settings.Server.AdminApiKey, apiKey) != 0) { _Logging.Warn(header + "admin API requested with invalid API key"); ctx.Response.StatusCode = 401; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(401, "Authentication failed.", null, null).ToJson(true)); return; } await AdminApiHandler(ctx); return; } #endregion #region Determine-Request-Type PermissionType permType = PermissionType.Unknown; if (ctx.Request.Url.Elements.Length == 1) { if (ctx.Request.Method == HttpMethod.GET && ctx.Request.Url.Elements[0].Equals("indices")) { // GET /indices, i.e. search permType = PermissionType.Search; } else if (ctx.Request.Method == HttpMethod.GET) { // GET /[index], i.e. search permType = PermissionType.Search; } else if (ctx.Request.Method == HttpMethod.PUT) { // PUT /[index], i.e. search // PUT /[index]?enumerate, i.e. search permType = PermissionType.Search; } else if (ctx.Request.Method == HttpMethod.POST) { if (ctx.Request.Url.Elements[0].Equals("_parse")) { // POST /_parse, i.e. parse document (without storing) permType = PermissionType.CreateDocument; } else if (ctx.Request.Url.Elements[0].Equals("_postings")) { // POST /_postings, i.e. create postings (without storing) permType = PermissionType.CreateDocument; } else if (ctx.Request.Url.Elements[0].Equals("indices")) { // POST /indices, i.e. create index permType = PermissionType.CreateIndex; } else { // POST /[index], i.e. create document permType = PermissionType.CreateDocument; } } else if (ctx.Request.Method == HttpMethod.DELETE) { // DELETE /[index], i.e. delete index permType = PermissionType.DeleteIndex; } } else if (ctx.Request.Url.Elements.Length == 2) { if (ctx.Request.Method == HttpMethod.GET) { if (ctx.Request.Url.Elements[1].Equals("stats")) { // GET /[index]/stats, i.e. search permType = PermissionType.Search; } else { // GET /[index]/[documentID], i.e. search permType = PermissionType.Search; } } else if (ctx.Request.Method == HttpMethod.POST) { // POST /[index]/[document], i.e. create document with specific GUID permType = PermissionType.CreateDocument; } else if (ctx.Request.Method == HttpMethod.DELETE) { // DELETE /[index]/[document], i.e. delete document permType = PermissionType.DeleteDocument; } } if (permType == PermissionType.Unknown) { _Logging.Warn(header + "unable to verify request type"); ctx.Response.StatusCode = 400; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(400, "Unable to discern request type.", null, null).ToJson(true)); return; } #endregion #region Authenticate-Request-and-Build-Metadata User user = null; ApiKey key = null; Permission perm = null; if (!String.IsNullOrEmpty(apiKey)) { if (!_Auth.AuthenticateAndAuthorize(apiKey, permType, out user, out key, out perm)) { _Logging.Warn(header + "unable to authenticate and authorize request"); ctx.Response.StatusCode = 401; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(401, "Unable to authenticate or authorize request.", null, null).ToJson(true)); return; } } else { _Logging.Warn(header + "authenticated API requested but no authentication material supplied"); ctx.Response.StatusCode = 401; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(401, "No authentication material.", null, null).ToJson(true)); return; } RequestMetadata md = new RequestMetadata(ctx, user, key, perm); if (!String.IsNullOrEmpty(md.Params.Type)) { List <string> matchVals = new List <string> { "json", "xml", "html", "sql", "text", "unknown" }; if (!matchVals.Contains(md.Params.Type)) { _Logging.Warn(header + "invalid 'type' value found in querystring: " + md.Params.Type); ctx.Response.StatusCode = 400; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(400, "Invalid 'type' in querystring, use [json/xml/html/sql/text].", null, null).ToJson(true)); return; } } #endregion #region Call-User-API await UserApiHandler(md); return; #endregion } catch (Exception e) { _Logging.Alert(header + "exception encountered" + Environment.NewLine + Common.SerializeJson(e, true)); ctx.Response.StatusCode = 500; ctx.Response.ContentType = "application/json"; await ctx.Response.Send(new ErrorResponse(500, "Outer exception.", e, null).ToJson(true)); return; } finally { _Logging.Debug(header + ctx.Request.Method + " " + ctx.Request.Url.RawWithoutQuery + " " + ctx.Response.StatusCode + " [" + Common.TotalMsFrom(startTime) + "ms]"); } }