private void HandleLogout(HttpListenerContext context) { var token = RestMethods.GetToken(context.Request); if (!_tokens.TryRemove(token, out var id)) { RestMethods.WriteError(context.Response, HttpStatusCode.Unauthorized, "Authorization failed"); return; } _users.TryRemove(id, out var user); _usernames.TryRemove(user.Username, out id); SendToAllSubscribers(WebSocketJsonType.DeletedResource, new DeletedItem { Item = user, Type = WebSocketJsonType.User }); context.Response.StatusCode = (int)HttpStatusCode.NoContent; context.Response.OutputStream.Close(); }
private void Subscribe(HttpListenerContext context) { if (!context.Request.IsWebSocketRequest) { RestMethods.WriteError(context.Response, HttpStatusCode.BadRequest, "not web socket request"); return; } if (!RestMethods.ParseQuery(context.Request.Url.Query, out Dictionary <string, string> query) || query == null || query.Count == 0 || !query.ContainsKey("token")) { RestMethods.WriteError(context.Response, HttpStatusCode.BadRequest, "missing token parameter"); return; } var wsContext = context.AcceptWebSocketAsync(null).Result; if (!_tokens.TryGetValue(query["token"], out int userId)) { RestMethods.WriteError(context.Response, HttpStatusCode.Unauthorized, "no match for token value"); return; } var segment = ConvertToBytesWithType(WebSocketJsonType.Users, _users.Values); wsContext.WebSocket.SendAsync(segment, WebSocketMessageType.Binary, false, CancellationToken.None).Wait(); lock (_webSockets) { var cancellationTask = wsContext.WebSocket.ReceiveAsync(new ArraySegment <byte>(new byte[1024]), CancellationToken.None); _webSockets.Add(wsContext.WebSocket, new Pair <int, Task> { First = userId, Second = cancellationTask }); } }
private void HandleLogin(HttpListenerContext context) { LoginRequest request; try { request = RestMethods.ReadBody <LoginRequest>(context.Request); } catch (ArgumentException e) { RestMethods.WriteError(context.Response, HttpStatusCode.BadRequest, e.Message); return; } if (_usernames.TryGetValue(request.Username, out int id)) { if (_users[id].Online) { context.Response.AppendHeader(HttpResponseHeader.WwwAuthenticate.ToString(), "Token realm = 'Username is already in use'"); RestMethods.WriteError(context.Response, HttpStatusCode.Unauthorized, "username is already in use"); return; } _users.TryRemove(id, out _); _usernames.TryRemove(request.Username, out id); _tokens.TryRemove(_tokens.First(tokenId => tokenId.Value == id).Key, out id); } lock (this) { id = ++_userId; } var token = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) .TrimEnd(Padding) .Replace('+', '-') .Replace('/', '_'); var loginResponse = new LoginResponse { Username = request.Username, Id = id, Online = true, Token = token }; var user = new User { Username = loginResponse.Username, Id = id, Online = true }; lock (_usernames) { if (!_usernames.TryAdd(loginResponse.Username, id)) { context.Response.AppendHeader(HttpResponseHeader.WwwAuthenticate.ToString(), "Token realm = 'Username is already in use'"); RestMethods.WriteError(context.Response, HttpStatusCode.Unauthorized, "username is already in use"); } _users.TryAdd(id, user); _tokens.TryAdd(token, id); } SendToAllSubscribers(WebSocketJsonType.User, user); RestMethods.WriteToResponse(context.Response, loginResponse); }
void Run() { Router router = new Router(); RestMethods restMethods = new RestMethods(VerifyToken); router.AddHandler("/subscribe", HttpMethod.Get, Subscribe); router.AddHandler("/login", HttpMethod.Post, HandleLogin); router.AddHandler("/logout", HttpMethod.Post, HandleLogout); router.AddHandler("/users", HttpMethod.Get, (context) => { restMethods.PerformGet <User>(context, GetUsersByQuery); } ); router.AddHandler("/users/" + Router.IntegerUrlParameter, HttpMethod.Get, (context) => restMethods.PerformGetById <User>(context, _users.TryGetValue, context.Request.Url.Segments[2]) ); router.AddHandler("/messages", HttpMethod.Post, (context) => restMethods.PerformPost <Message>(context, AddMessage) ); router.AddHandler("/messages", HttpMethod.Get, (context) => { restMethods.PerformGet <Message>(context, GetMessagesByQuery); } ); router.AddHandler("/messages/" + Router.IntegerUrlParameter, HttpMethod.Get, (context) => restMethods.PerformGetById <Message>(context, _messages.TryGetValue, context.Request.Url.Segments[2]) ); router.AddHandler("/messages/" + Router.IntegerUrlParameter, HttpMethod.Delete, (context) => restMethods.PerformDelete(context, DeleteMessage, context.Request.Url.Segments[2]) ); using (HttpListener httpListener = new HttpListener()) { httpListener.Prefixes.Add("http://localhost:" + _port + "/"); httpListener.Start(); while (true) { var context = httpListener.GetContext(); var request = context.Request; var t = new Thread(() => { if (router.TryGetHandler(request, out HandlerFunc handler)) { handler(context); } else { RestMethods.WriteError(context.Response, HttpStatusCode.BadRequest, "no handler provided"); } }); t.Start(); } } }
private bool VerifyToken(HttpListenerRequest request) { var token = RestMethods.GetToken(request); return(_tokens.ContainsKey(token)); }