static int is_keep_alive(struct http_message *hm) { const struct mg_str *connection_header = mg_get_http_header(hm, "Connection"); if (connection_header == NULL) { /* HTTP/1.1 connections are keep-alive by default. */ if (mg_vcasecmp(&hm->proto, "HTTP/1.1") != 0) return 0; } else if (mg_vcasecmp(connection_header, "keep-alive") != 0) { return 0; } // We must also have Content-Length. return mg_get_http_header(hm, "Content-Length") != NULL; }
/* * These functions are for V1 of the protocol */ static void upload_handler_v1(struct mg_connection *nc, int ev, void *p) { struct mg_str *filename, *data; struct http_message *hm; size_t length; char buf[16]; int fd; switch (ev) { case MG_EV_HTTP_REQUEST: hm = (struct http_message *) p; filename = mg_get_http_header(hm, "X_FILENAME"); if (filename == NULL) { mg_http_send_error(nc, 403, NULL); return; } data = mg_get_http_header(hm, "Content-length"); if (data == NULL || data->len >= ARRAY_SIZE(buf)) { mg_http_send_error(nc, 403, NULL); return; } memcpy(buf, data->p, data->len); buf[data->len] = '\0'; length = strtoul(data->p, NULL, 10); if (length == 0) { mg_http_send_error(nc, 403, NULL); return; } fd = ipc_inst_start_ext(SOURCE_WEBSERVER, filename->len, filename->p, false); ipc_send_data(fd, (char *) hm->body.p, hm->body.len); ipc_end(fd); mg_send_response_line(nc, 200, "Content-Type: text/plain\r\n" "Connection: close"); mg_send(nc, "\r\n", 2); mg_printf(nc, "Ok, %.*s - %d bytes.\r\n", (int) filename->len, filename->p, (int) length); nc->flags |= MG_F_SEND_AND_CLOSE; break; default: upload_handler(nc, ev, p); break; } }
static struct http_backend *choose_backend_from_list( struct http_message *hm, struct http_backend *backends, int num_backends) { int i; struct mg_str vhost = {"", 0}; const struct mg_str *host = mg_get_http_header(hm, "host"); if (host != NULL) vhost = *host; const char *vhost_end = vhost.p; while (vhost_end < vhost.p + vhost.len && *vhost_end != ':') { vhost_end++; } vhost.len = vhost_end - vhost.p; struct http_backend *chosen = NULL; for (i = 0; i < num_backends; i++) { struct http_backend *be = &backends[i]; if (has_prefix(&hm->uri, be->uri_prefix) && matches_vhost(&vhost, be->vhost) && (chosen == NULL || /* Prefer most specific URI prefixes */ strlen(be->uri_prefix) > strlen(chosen->uri_prefix) || /* Among prefixes of the same length chose the least used. */ (strlen(be->uri_prefix) == strlen(chosen->uri_prefix) && be->usage_counter < chosen->usage_counter))) { chosen = be; } } return chosen; }
void Server::authorize(struct mg_connection *conn, struct http_message *hm) { Server::session *session; std::string user = get_http_var(hm, "user"); std::string password = get_http_var(hm, "password"); std::string host; mg_str *host_hdr = mg_get_http_header(hm, "Host"); if (host_hdr) { if (!CONFIG_STRING(m_config, "service.cert").empty()) { host += "https://"; } else { host += "http://"; } host += std::string(host_hdr->p, host_hdr->len); } if (check_password(user, password) && (session = new_session(user)) != NULL) { std::cout << "User authorized\n"; mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID "Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code "Set-Cookie: admin=%s\r\n" // Set user, needed by Javascript code "Set-Cookie: base_location=%s\r\n" // Set user, needed by Javascript code "Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url "Location: %s%sinstances\r\n\r\n", session->session_id, session->user, session->admin ? "1" : "0", CONFIG_STRING(m_config, "service.base_location").c_str(), host.c_str(), CONFIG_STRING(m_config, "service.base_location").c_str()); } else { // Authentication failure, redirect to login. redirect_to(conn, hm, "/login"); } }
std::string ccMongooseWebServerRequest::GetHeader(const std::string& name) { if (_pMgHttpMessage == NULL) return _strNullData; struct mg_str* pResult = mg_get_http_header(_pMgHttpMessage, name.c_str()); if (pResult == NULL) return _strNullData; std::string strHeader(pResult->p, pResult->len); return strHeader; }
// Get session object for the connection. Caller must hold the lock. Server::session *Server::get_session(struct http_message *hm) { time_t now = time(NULL); char session_id[255]; struct mg_str *hdr = mg_get_http_header(hm, "Cookie"); int len = mg_http_parse_header(hdr, "session", session_id, sizeof(session_id)); session_id[len] = 0; if (sessions.find(session_id) == sessions.end()) { return NULL; } if (sessions[session_id]->expire != 0 && sessions[session_id]->expire > now) { return sessions[session_id]; } return NULL; }
/* * Parses the session cookie and returns a pointer to the session struct * or NULL if not found. */ static struct session *get_session(struct http_message *hm) { struct mg_str *cookie_header = mg_get_http_header(hm, "cookie"); if (cookie_header == NULL) return NULL; char ssid[21]; if (!mg_http_parse_header(cookie_header, SESSION_COOKIE_NAME, ssid, sizeof(ssid))) { return NULL; } uint64_t sid = strtoull(ssid, NULL, 16); for (int i = 0; i < NUM_SESSIONS; i++) { if (s_sessions[i].id == sid) { s_sessions[i].last_used = mg_time(); return &s_sessions[i]; } } return NULL; }
void Server::redirect_to(struct mg_connection *conn, struct http_message *hm, const char *where) { std::string host; mg_str *host_hdr = mg_get_http_header(hm, "Host"); if (host_hdr) { if (!CONFIG_STRING(m_config, "service.cert").empty()) { host += "https://"; } else { host += "http://"; } host += std::string(host_hdr->p, host_hdr->len); } where = where + 1; mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: original_url=/\r\n" "Location: %s%s%s\r\n\r\n", host.c_str(), CONFIG_STRING(m_config, "service.base_location").c_str(), where); }
bool RestServ::remove_from_session_list(HttpMessage data) { mg_str* cookie_header = mg_get_http_header(data.get(), "cookie");; if (cookie_header == nullptr) return false; char ssid[32]{0x00}; if (!mg_http_parse_header(cookie_header, SESSION_COOKIE_NAME, ssid, sizeof(ssid))) return false; auto sid = std::stoul(ssid, nullptr, 10); for (auto iter = session_list_.begin(); iter != session_list_.end(); ++iter) { if ( (*iter)->id == sid ) { iter = session_list_.erase(iter); } } return true; }
std::shared_ptr<Session> RestServ::get_from_session_list(HttpMessage data) { mg_str* cookie_header = mg_get_http_header(data.get(), "cookie");; if (cookie_header == nullptr) return nullptr; char ssid[32]{0x00}; if (!mg_http_parse_header(cookie_header, SESSION_COOKIE_NAME, ssid, sizeof(ssid))) return nullptr; auto sid = std::stoul(ssid, nullptr, 10); auto ret = std::find_if(session_list_.begin(), session_list_.end(), [&sid](std::shared_ptr<Session> p){ return sid == p->id; }); if (ret == session_list_.end()) return nullptr; (*ret)->last_used = mg_time(); return *ret; }
void Server::serve_logout(struct mg_connection *conn, struct http_message *hm) { std::string host; mg_str *host_hdr = mg_get_http_header(hm, "Host"); if (host_hdr) { if (!CONFIG_STRING(m_config, "service.cert").empty()) { host += "https://"; } else { host += "http://"; } host += std::string(host_hdr->p, host_hdr->len); } Server:session *session = get_session(hm); mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: session=%s; max-age=0\r\n" "Set-Cookie: admin=%s; max-age=0\r\n" "Location: %s%s\r\n\r\n", session->session_id, session->admin ? "1" : "0", host.c_str(), CONFIG_STRING(m_config, "service.base_location").c_str()); sessions.erase(session->session_id); delete session; }
void UpdateUserData::handle(Manager* manager, SharedManager* sManager) { bool validation = this->validateInput(); if(validation) { struct mg_str *cl_header = mg_get_http_header(hm, "Token"); if(!cl_header) { this->response(1, "Token Missing ", returnEmptyJsonObject()); return; } Json::Reader r = Json::Reader(); Json::Value value = Json::Value(); r.parse(hm->body.p, value); // Local user update User* user = manager->getUser(value.get("username","").asString()); if(!user) { this->response(1, "User could not be modified", returnEmptyJsonObject()); return; } std::string token(getHeaderParam(cl_header->p)); if(token.compare(user->getToken()) != 0) { this->response(2, "Invalid Token", returnEmptyJsonObject()); return; } user->updateWithJson(value); bool updateUser = manager->updateUser(user); if(updateUser) { value["id"] = user->getId(); if(value.isMember("photoProfile") || value.isMember("photo_profile")) { // Photo Profile Upload std::string key = ""; value.isMember("photoProfile") ? key = "photoProfile" : key = "photo_profile"; Json::Value uploadP = Json::Value(); uploadP["photo"] = value.get(key, "").asString(); uploadP["id"] = user->getId(); value.removeMember(key); int photoUp = sManager->putUserPhoto(uploadP); if(!photoUp) { this->response(1, "User photo profile could not be uploaded", returnEmptyJsonObject()); return; } } // Rest of user data to update on Shared Server // TODO: Falta subir los intereses nuevos que haya! if(value.isMember("interests")) { Json::Value interests = value.get("interests", Json::Value(Json::arrayValue)); Json::ValueConstIterator interestsIt = interests.begin(); while(interestsIt != interests.end()) { Json::Value response = sManager->postInterest(*interestsIt); // TODO: Alguna cola para reupload de intereses que debieron subir // pero no pudieron por algun problema (que no sea duplicado) interestsIt++; } } if(value.isMember("edad")) value["age"] = value.get("edad", 18).asInt(); int sharedUpdate = sManager->putUser(value); if(sharedUpdate) { this->response(0, "Modified", user->getJson()); } else { this->response(1, "User could not be modified", returnEmptyJsonObject()); } } else { this->response(1, "User could not be modified", returnEmptyJsonObject()); } delete user; } }
static void mg_ev_handler(struct mg_connection *nc, int ev, void *ev_data) { switch (ev) { case MG_EV_ACCEPT: { char addr[32]; mg_conn_addr_to_str(nc, addr, sizeof(addr), MG_SOCK_STRINGIFY_REMOTE | MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); LOG(LL_INFO, ("%p conn from %s", nc, addr)); break; } case MG_EV_HTTP_REQUEST: { char addr[32]; struct http_message *hm = (struct http_message *) ev_data; cs_stat_t st; mg_conn_addr_to_str(nc, addr, sizeof(addr), MG_SOCK_STRINGIFY_REMOTE | MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); LOG(LL_INFO, ("HTTP request from %s: %.*s %.*s", addr, (int) hm->method.len, hm->method.p, (int) hm->uri.len, hm->uri.p)); if (mg_vcmp(&hm->uri, "/upload") == 0 || (mg_vcmp(&hm->uri, "/") == 0 && mg_stat("SL:index.html", &st) != 0)) { mg_send(nc, upload_form, strlen(upload_form)); nc->flags |= MG_F_SEND_AND_CLOSE; break; } struct mg_serve_http_opts opts; memset(&opts, 0, sizeof(opts)); opts.document_root = "SL:"; mg_serve_http(nc, hm, opts); break; } case MG_EV_CLOSE: { LOG(LL_INFO, ("%p closed", nc)); break; } case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { LOG(LL_INFO, ("%p switching to data mode", nc)); nc->handler = data_conn_handler; nc->ev_timer_time = mg_time(); /* Immediately */ break; } case MG_EV_TIMER: { data_collect(); nc->ev_timer_time = mg_time() + (DATA_COLLECTION_INTERVAL_MS * 0.001); break; } /* SimpleLink FS requires pre-declaring max file size. We use Content-Length * for that purpose - it will not exactly match file size, but is guaranteed * to exceed it and should be close enough. */ case MG_EV_HTTP_MULTIPART_REQUEST: { struct http_message *hm = (struct http_message *) ev_data; struct mg_str *cl_header = mg_get_http_header(hm, "Content-Length"); intptr_t cl = -1; if (cl_header != NULL && cl_header->len < 20) { char buf[20]; memcpy(buf, cl_header->p, cl_header->len); buf[cl_header->len] = '\0'; cl = atoi(buf); if (cl < 0) cl = -1; } nc->user_data = (void *) cl; break; } case MG_EV_HTTP_PART_BEGIN: case MG_EV_HTTP_PART_DATA: case MG_EV_HTTP_PART_END: { struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) ev_data; if (ev == MG_EV_HTTP_PART_BEGIN) { LOG(LL_INFO, ("Begin file upload: %s", mp->file_name)); } else if (ev == MG_EV_HTTP_PART_END) { LOG(LL_INFO, ("End file upload: %s", mp->file_name)); } mg_file_upload_handler(nc, ev, ev_data, upload_fname); } } }