<commit_before>#include "clustering/administration/http/combining_app.hpp"

#include "http/json.hpp"
#include "logger.hpp"

combining_http_app_t::combining_http_app_t(std::map<std::string, http_json_app_t *> components_)
	: components(components_) { }

http_res_t combining_http_app_t::handle(const http_req_t &req) {
    typedef std::map<std::string, http_json_app_t *>::const_iterator components_iterator;
    std::string resource = req.resource.as_string();
    if (resource != "/" && resource != "") {
        return http_res_t(404);
    }

    scoped_cJSON_t json(cJSON_CreateObject());
    for (components_iterator it = components.begin(); it != components.end(); ++it) {
        scoped_cJSON_t child_json(NULL), req_json(NULL);
        cJSON *subpost;
        switch(req.method) {
        case GET:
            it->second->get_root(&child_json);
            break;

        case POST:
            req_json.reset(cJSON_Parse(req.body.c_str()));
            if (!req_json.get() || req_json.get()->type != cJSON_Object) {
                logINF("JSON body failed to parse as object: %s",
                       req.get_sanitized_body().c_str());
                return http_res_t(400);
            }

            subpost = cJSON_GetObjectItem(req_json.get(), it->first.c_str());
            if (subpost) {
                http_req_t subreq = req;
                subreq.body = cJSON_PrintUnformatted(subpost);
                child_json.reset(cJSON_Parse(it->second->handle(subreq).body.c_str()));
            } else {
                it->second->get_root(&child_json);
            }
            break;

        case PUT: case DELETE:
        case HEAD: case TRACE: case OPTIONS: case CONNECT: case PATCH:
        default: return http_res_t(405);
        }
        cJSON_AddItemToObject(json.get(), it->first.c_str(), child_json.release());
    }

    http_res_t res(200);
    res.set_body("application/json", cJSON_print_std_string(json.get()));<commit_msg>Modified [handle] in combining_app.cc so that POST requests invoke the handlers for all subapps before the JSON of those subapps is retrieved, allowing cross-subapp changes to propagate regardless of order.<commit_after>#include "clustering/administration/http/combining_app.hpp"

#include "http/json.hpp"
#include "logger.hpp"

combining_http_app_t::combining_http_app_t(std::map<std::string, http_json_app_t *> components_)
	: components(components_) { }

http_res_t combining_http_app_t::handle(const http_req_t &req) {
    typedef std::map<std::string, http_json_app_t *>::const_iterator components_iterator;

    std::string resource = req.resource.as_string();
    if (resource != "/" && resource != "") return http_res_t(404);

    if (req.method == POST) {
        scoped_cJSON_t req_json(cJSON_Parse(req.body.c_str()));
        if (!req_json.get() || req_json.get()->type != cJSON_Object) {
            logINF("JSON body failed to parse as object: %s",
                   req.get_sanitized_body().c_str());
            return http_res_t(400);
        }
        for (components_iterator it = components.begin(); it != components.end(); ++it) {
            cJSON *subpost = cJSON_GetObjectItem(req_json.get(), it->first.c_str());
            if (subpost) {
                http_req_t subreq = req;
                subreq.body = cJSON_PrintUnformatted(subpost);
                /* We discard the result of [handle] because it might change
                   when we handle a later request. */
                it->second->handle(subreq);
            }
        }
    }

    /* Throwing away the results of [handle] above and calling [get_root] after
       everything has been handled allows changes to one app that affect another
       app in the combiner to propagate. */
    scoped_cJSON_t json(cJSON_CreateObject());
    for (components_iterator it = components.begin(); it != components.end(); ++it) {
        scoped_cJSON_t child_json(NULL);
        it->second->get_root(&child_json);
        cJSON_AddItemToObject(json.get(), it->first.c_str(), child_json.release());
    }

    http_res_t res(200);
    res.set_body("application/json", cJSON_print_std_string(json.get()));
{'fraction_non_alphanumeric': 0.1268386785628165, 'fraction_numerical': 0.0050639016156257535, 'mean_word_length': 2.8550185873605947, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '671074', 'n_tokens_mistral': 1320, 'n_tokens_neox': 1266, 'n_words': 260}