Merge pull request #340 from kiwix/perf_kiwix_serve

Perf kiwix serve
pull/9/head
Kelson 10 years ago committed by GitHub
commit a53dea6d1e

@ -144,79 +144,162 @@ bool isVerbose() {
static Bytef *compr = (Bytef *)malloc(COMPRESSOR_BUFFER_SIZE); static Bytef *compr = (Bytef *)malloc(COMPRESSOR_BUFFER_SIZE);
static uLongf comprLen; static uLongf comprLen;
static int accessHandlerCallback(void *cls,
struct MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** ptr) {
/* Unexpected method */ static
if (0 != strcmp(method, "GET") && 0 != strcmp(method, "POST")) bool compress_content(string &content,
return MHD_NO; const string &mimeType)
{
/* Compute the lengh */
unsigned int contentLength = content.size();
/* The first time only the headers are valid, do not respond in the first round... */ /* Should be deflate */
static int dummy; bool deflated =
if (&dummy != *ptr) { contentLength > KIWIX_MIN_CONTENT_SIZE_TO_DEFLATE &&
*ptr = &dummy; contentLength < COMPRESSOR_BUFFER_SIZE &&
return MHD_YES; (mimeType.find("text/") != string::npos ||
} mimeType.find("application/javascript") != string::npos ||
mimeType.find("application/json") != string::npos);
/* Debug */ /* Compress the content if necessary */
if (isVerbose()) { if (deflated) {
std::cout << "Requesting " << url << std::endl; pthread_mutex_lock(&compressorLock);
comprLen = COMPRESSOR_BUFFER_SIZE;
compress(compr, &comprLen, (const Bytef*)(content.data()), contentLength);
if (comprLen > 2 && comprLen < contentLength) {
/* /!\ Internet Explorer has a bug with deflate compression.
It can not handle the first two bytes (compression headers)
We need to chunk them off (move the content 2bytes)
It has no incidence on other browsers
See http://www.subbu.org/blog/2008/03/ie7-deflate-or-not and comments */
compr += 2;
content = string((char *)compr, comprLen);
contentLength = comprLen;
} else {
deflated = false;
} }
/* Check if the response can be compressed */ pthread_mutex_unlock(&compressorLock);
const string acceptEncodingHeaderValue = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_ENCODING) ? }
MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_ENCODING) : ""; return deflated;
const bool acceptEncodingDeflate = !acceptEncodingHeaderValue.empty() && acceptEncodingHeaderValue.find("deflate") != string::npos; }
/* Check if range is requested */
const string acceptRangeHeaderValue = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE) ?
MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE) : "";
const bool acceptRange = !acceptRangeHeaderValue.empty();
/* Prepare the variables */ static
struct MHD_Response *response; struct MHD_Response* build_response(const void* data,
std::string content; unsigned int length,
std::string mimeType; const std::string& httpRedirection,
std::string httpRedirection; const std::string& mimeType,
unsigned int contentLength = 0; bool deflated,
bool cacheEnabled = true; bool cacheEnabled)
int httpResponseCode = MHD_HTTP_OK; {
std::string urlStr = string(url); /* Create the response */
struct MHD_Response * response = MHD_create_response_from_data(length,
const_cast<void*>(data),
MHD_NO,
MHD_YES);
/* Get searcher and reader */ /* Make a redirection if necessary otherwise send the content */
std::string humanReadableBookId = ""; if (!httpRedirection.empty()) {
if (!(urlStr.size() > 5 && urlStr.substr(0, 6) == "/skin/")) { MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, httpRedirection.c_str());
if (!strcmp(url, "/search") || !strcmp(url, "/suggest") || !strcmp(url, "/random")) {
const char* tmpGetValue = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "content");
humanReadableBookId = (tmpGetValue != NULL ? string(tmpGetValue) : "");
} else { } else {
humanReadableBookId = urlStr.substr(1, urlStr.find("/", 1) != string::npos ?
urlStr.find("/", 1) - 1 : urlStr.size() - 2); /* Add if necessary the content-encoding */
if (!humanReadableBookId.empty()) { if (deflated) {
urlStr = urlStr.substr(urlStr.find("/", 1) != string::npos ? MHD_add_response_header(response, MHD_HTTP_HEADER_VARY, "Accept-Encoding");
urlStr.find("/", 1) : humanReadableBookId.size()); MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate");
}
/* Tell the client that byte ranges are accepted */
MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes");
/* Specify the mime type */
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimeType.c_str());
} }
/* Force to close the connection - cf. 100% CPU usage with v. 4.4 (in Lucid) */
//MHD_add_response_header(response, MHD_HTTP_HEADER_CONNECTION, "close");
/* Allow cross-domain requests */
//MHD_add_response_header(response, MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
if (cacheEnabled) { /* Force cache */
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, "max-age=2723040, public");
} else { /* Prevent cache (for random page) */
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, "no-cache, no-store, must-revalidate");
} }
return response;
} }
pthread_mutex_lock(&mapLock); ssize_t callback_reader_from_blob(void *cls,
kiwix::Searcher *searcher = searchers.find(humanReadableBookId) != searchers.end() ? uint64_t pos,
searchers.find(humanReadableBookId)->second : NULL; char *buf,
kiwix::Reader *reader = readers.find(humanReadableBookId) != readers.end() ? size_t max)
readers.find(humanReadableBookId)->second : NULL; {
if (reader == NULL) { zim::Blob* blob = static_cast<zim::Blob*>(cls);
humanReadableBookId=""; pthread_mutex_lock(&readerLock);
size_t max_size_to_set = min(max, blob->size()-pos);
if (max_size_to_set <= 0)
{
pthread_mutex_unlock(&readerLock);
return MHD_CONTENT_READER_END_WITH_ERROR;
} }
pthread_mutex_unlock(&mapLock);
/* Get suggestions */ memcpy(buf, blob->data()+pos, max_size_to_set);
if (!strcmp(url, "/suggest") && reader != NULL) { pthread_mutex_unlock(&readerLock);
return max_size_to_set;
}
void callback_free_blob(void *cls)
{
zim::Blob* blob = static_cast<zim::Blob*>(cls);
pthread_mutex_lock(&readerLock);
delete blob;
pthread_mutex_unlock(&readerLock);
}
static
struct MHD_Response* build_callback_response_from_blob(zim::Blob& blob,
const std::string& mimeType)
{
pthread_mutex_lock(&readerLock);
zim::Blob* p_blob = new zim::Blob(blob);
struct MHD_Response * response = MHD_create_response_from_callback(blob.size(),
16384,
callback_reader_from_blob,
p_blob,
callback_free_blob);
pthread_mutex_unlock(&readerLock);
/* Tell the client that byte ranges are accepted */
MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes");
/* Specify the mime type */
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimeType.c_str());
/* Allow cross-domain requests */
//MHD_add_response_header(response, MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, "max-age=2723040, public");
return response;
}
static
struct MHD_Response* handle_suggest(struct MHD_Connection * connection,
int& httpResponseCode,
kiwix::Reader *reader,
kiwix::Searcher *searcher,
const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
std::string content;
std::string mimeType;
unsigned int maxSuggestionCount = 10; unsigned int maxSuggestionCount = 10;
unsigned int suggestionCount = 0; unsigned int suggestionCount = 0;
std::string suggestion; std::string suggestion;
@ -246,16 +329,37 @@ static int accessHandlerCallback(void *cls,
content += "]"; content += "]";
mimeType = "application/json; charset=utf-8"; mimeType = "application/json; charset=utf-8";
} bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), "", mimeType, deflated, true);
/* Get static skin stuff */ }
else if (urlStr.substr(0, 6) == "/skin/") {
content = getResourceAsString(urlStr.substr(6)); static
mimeType = getMimeTypeForFile(urlStr); struct MHD_Response* handle_skin(struct MHD_Connection * connection,
} int& httpResponseCode,
kiwix::Reader *reader,
/* Display the search restults */ kiwix::Searcher *searcher,
else if (!strcmp(url, "/search")) { const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
std::string content = getResourceAsString(urlStr.substr(6));
std::string mimeType = getMimeTypeForFile(urlStr);
bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), "", mimeType, deflated, true);
}
static
struct MHD_Response* handle_search(struct MHD_Connection * connection,
int& httpResponseCode,
kiwix::Reader *reader,
kiwix::Searcher *searcher,
const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
std::string content;
std::string mimeType;
std::string httpRedirection;
/* Retrieve the pattern to search */ /* Retrieve the pattern to search */
const char* pattern = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "pattern"); const char* pattern = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "pattern");
@ -277,6 +381,8 @@ static int accessHandlerCallback(void *cls,
/* If article found then redirect directly to it */ /* If article found then redirect directly to it */
if (!patternCorrespondingUrl.empty()) { if (!patternCorrespondingUrl.empty()) {
httpRedirection = "/" + humanReadableBookId + "/" + patternCorrespondingUrl; httpRedirection = "/" + humanReadableBookId + "/" + patternCorrespondingUrl;
httpResponseCode = MHD_HTTP_FOUND;
return build_response("", 0, httpRedirection, "", false, true);
} }
} }
@ -302,48 +408,115 @@ static int accessHandlerCallback(void *cls,
} }
mimeType = "text/html; charset=utf-8"; mimeType = "text/html; charset=utf-8";
introduceTaskbar(content, humanReadableBookId);
bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), httpRedirection, mimeType, deflated, true);
} }
/* Display a random article */ static
else if (!strcmp(url, "/random")) { struct MHD_Response* handle_random(struct MHD_Connection * connection,
cacheEnabled = false; int& httpResponseCode,
kiwix::Reader *reader,
kiwix::Searcher *searcher,
const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
std::string httpRedirection;
bool cacheEnabled = false;
httpResponseCode = MHD_HTTP_FOUND;
if (reader != NULL) { if (reader != NULL) {
pthread_mutex_lock(&readerLock); pthread_mutex_lock(&readerLock);
std::string randomUrl = reader->getRandomPageUrl(); std::string randomUrl = reader->getRandomPageUrl();
pthread_mutex_unlock(&readerLock); pthread_mutex_unlock(&readerLock);
httpRedirection = "/" + humanReadableBookId + "/" + kiwix::urlEncode(randomUrl); httpRedirection = "/" + humanReadableBookId + "/" + kiwix::urlEncode(randomUrl);
} }
return build_response("", 0, httpRedirection, "", false, false);
} }
/* Display the content of a ZIM content (article, image, ...) */ static
else if (reader != NULL) { struct MHD_Response* handle_content(struct MHD_Connection * connection,
int& httpResponseCode,
kiwix::Reader *reader,
kiwix::Searcher *searcher,
const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
std::string baseUrl; std::string baseUrl;
std::string content;
std::string mimeType;
unsigned int contentLength;
try { bool found = false;
zim::Article article;
pthread_mutex_lock(&readerLock); pthread_mutex_lock(&readerLock);
bool found = reader->getContentByDecodedUrl(urlStr, content, contentLength, mimeType, baseUrl); try {
pthread_mutex_unlock(&readerLock); found = reader->getArticleObjectByDecodedUrl(urlStr, article);
if (found) { if (found) {
if (isVerbose()) { /* If redirect */
cout << "Found " << urlStr << endl; unsigned int loopCounter = 0;
cout << "content size: " << contentLength << endl; while (article.isRedirect() && loopCounter++<42) {
cout << "mimeType: " << mimeType << endl; article = article.getRedirectArticle();
} }
} else {
/* To many loop */
if (loopCounter == 42)
found = false;
}
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
found = false;
}
pthread_mutex_unlock(&readerLock);
if (!found) {
if (isVerbose()) if (isVerbose())
cout << "Failed to find " << urlStr << endl; cout << "Failed to find " << urlStr << endl;
content = "<!DOCTYPE html>\n<html><head><meta content=\"text/html;charset=UTF-8\" http-equiv=\"content-type\" /><title>Content not found</title></head><body><h1>Not Found</h1><p>The requested URL \"" + urlStr + "\" was not found on this server.</p></body></html>"; content = "<!DOCTYPE html>\n<html><head><meta content=\"text/html;charset=UTF-8\" http-equiv=\"content-type\" /><title>Content not found</title></head><body><h1>Not Found</h1><p>The requested URL \"" + urlStr + "\" was not found on this server.</p></body></html>";
mimeType = "text/html"; mimeType = "text/html";
httpResponseCode = MHD_HTTP_NOT_FOUND; httpResponseCode = MHD_HTTP_NOT_FOUND;
introduceTaskbar(content, humanReadableBookId);
bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), "", mimeType, deflated, false);
} }
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl; try {
pthread_mutex_lock(&readerLock);
mimeType = article.getMimeType();
pthread_mutex_unlock(&readerLock);
} catch (exception &e) {
mimeType = "application/octet-stream";
} }
if (isVerbose()) {
cout << "Found " << urlStr << endl;
cout << "mimeType: " << mimeType << endl;
}
pthread_mutex_lock(&readerLock);
zim::Blob raw_content = article.getData();
pthread_mutex_unlock(&readerLock);
if (mimeType.find("text/") != string::npos ||
mimeType.find("application/javascript") != string::npos ||
mimeType.find("application/json") != string::npos)
{
pthread_mutex_lock(&readerLock);
content = string(raw_content.data(), raw_content.size());
pthread_mutex_unlock(&readerLock);
/* Special rewrite URL in case of ZIM file use intern *asbolute* url like /A/Kiwix */ /* Special rewrite URL in case of ZIM file use intern *asbolute* url like /A/Kiwix */
if (mimeType.find("text/html") != string::npos) { if (mimeType.find("text/html") != string::npos) {
if (content.find("<body") == std::string::npos &&
content.find("<BODY") == std::string::npos) {
content = "<html><head><title>" + article.getTitle() + "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>" + content + "</body></html>";
}
baseUrl = "/" + std::string(1, article.getNamespace()) + "/" + article.getUrl();
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/", content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
"(href|src)(=[\"|\']{0,1}/)([A-Z|\\-])/"); "(href|src)(=[\"|\']{0,1}/)([A-Z|\\-])/");
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/", content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
@ -351,100 +524,171 @@ static int accessHandlerCallback(void *cls,
content = replaceRegex(content, content = replaceRegex(content,
"<head><base href=\"/" + humanReadableBookId + baseUrl + "\" />", "<head><base href=\"/" + humanReadableBookId + baseUrl + "\" />",
"<head>"); "<head>");
introduceTaskbar(content, humanReadableBookId);
} else if (mimeType.find("text/css") != string::npos) { } else if (mimeType.find("text/css") != string::npos) {
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/", content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
"(url|URL)(\\([\"|\']{0,1}/)([A-Z|\\-])/"); "(url|URL)(\\([\"|\']{0,1}/)([A-Z|\\-])/");
} }
bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), "", mimeType, deflated, true);
}
else
{
return build_callback_response_from_blob(raw_content, mimeType);
}
} }
/* Display the global Welcome page */ static
else { struct MHD_Response* handle_default(struct MHD_Connection * connection,
int& httpResponseCode,
kiwix::Reader *reader,
kiwix::Searcher *searcher,
const std::string& urlStr,
const std::string& humanReadableBookId,
bool acceptEncodingDeflate)
{
pthread_mutex_lock(&welcomeLock); pthread_mutex_lock(&welcomeLock);
content = welcomeHTML; std::string content = welcomeHTML;
pthread_mutex_unlock(&welcomeLock); pthread_mutex_unlock(&welcomeLock);
mimeType = "text/html; charset=utf-8";
std::string mimeType = "text/html; charset=utf-8";
bool deflated = acceptEncodingDeflate && compress_content(content, mimeType);
return build_response(content.data(), content.size(), "", mimeType, deflated, true);
} }
/* Introduce Taskbar */ static int accessHandlerCallback(void *cls,
if (!humanReadableBookId.empty() && mimeType.find("text/html") != string::npos) { struct MHD_Connection * connection,
introduceTaskbar(content, humanReadableBookId); const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** ptr)
{
/* Unexpected method */
if (0 != strcmp(method, "GET") && 0 != strcmp(method, "POST"))
return MHD_NO;
/* The first time only the headers are valid, do not respond in the first round... */
static int dummy;
if (&dummy != *ptr) {
*ptr = &dummy;
return MHD_YES;
} }
/* Compute the lengh */ /* clear context pointer */
contentLength = content.size(); *ptr = NULL;
/* Should be deflate */ /* Debug */
bool deflated = if (isVerbose()) {
contentLength > KIWIX_MIN_CONTENT_SIZE_TO_DEFLATE && std::cout << "Requesting " << url << std::endl;
contentLength < COMPRESSOR_BUFFER_SIZE && }
acceptEncodingDeflate &&
(mimeType.find("text/") != string::npos ||
mimeType.find("application/javascript") != string::npos ||
mimeType.find("application/json") != string::npos);
/* Compress the content if necessary */ /* Check if the response can be compressed */
if (deflated) { const char* acceptEncodingHeaderValue = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_ENCODING);
pthread_mutex_lock(&compressorLock); const bool acceptEncodingDeflate = acceptEncodingHeaderValue && string(acceptEncodingHeaderValue).find("deflate") != string::npos;
comprLen = COMPRESSOR_BUFFER_SIZE;
compress(compr, &comprLen, (const Bytef*)(content.data()), contentLength);
if (comprLen > 2 && comprLen < contentLength) { /* Check if range is requested */
const char* acceptRangeHeaderValue = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE);
const bool acceptRange = acceptRangeHeaderValue != NULL;
/* /!\ Internet Explorer has a bug with deflate compression. /* Prepare the variables */
It can not handle the first two bytes (compression headers) struct MHD_Response *response;
We need to chunk them off (move the content 2bytes) int httpResponseCode = MHD_HTTP_OK;
It has no incidence on other browsers std::string urlStr = string(url);
See http://www.subbu.org/blog/2008/03/ie7-deflate-or-not and comments */
compr += 2;
content = string((char *)compr, comprLen); /* Get searcher and reader */
contentLength = comprLen; std::string humanReadableBookId = "";
if (!(urlStr.size() > 5 && urlStr.substr(0, 6) == "/skin/")) {
if (!strcmp(url, "/search") || !strcmp(url, "/suggest") || !strcmp(url, "/random")) {
const char* tmpGetValue = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "content");
humanReadableBookId = (tmpGetValue != NULL ? string(tmpGetValue) : "");
} else { } else {
deflated = false; humanReadableBookId = urlStr.substr(1, urlStr.find("/", 1) != string::npos ?
urlStr.find("/", 1) - 1 : urlStr.size() - 2);
if (!humanReadableBookId.empty()) {
urlStr = urlStr.substr(urlStr.find("/", 1) != string::npos ?
urlStr.find("/", 1) : humanReadableBookId.size());
}
} }
pthread_mutex_unlock(&compressorLock);
} }
/* Create the response */ pthread_mutex_lock(&mapLock);
response = MHD_create_response_from_data(contentLength, kiwix::Searcher *searcher = searchers.find(humanReadableBookId) != searchers.end() ?
(void *)content.data(), searchers.find(humanReadableBookId)->second : NULL;
MHD_NO, kiwix::Reader *reader = readers.find(humanReadableBookId) != readers.end() ?
MHD_YES); readers.find(humanReadableBookId)->second : NULL;
if (reader == NULL) {
/* Make a redirection if necessary otherwise send the content */ humanReadableBookId="";
if (!httpRedirection.empty()) {
MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, httpRedirection.c_str());
httpResponseCode = MHD_HTTP_FOUND;
} else {
/* Add if necessary the content-encoding */
if (deflated) {
MHD_add_response_header(response, MHD_HTTP_HEADER_VARY, "Accept-Encoding");
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate");
} }
pthread_mutex_unlock(&mapLock);
/* Tell the client that byte ranges are accepted */ /* Get suggestions */
MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes"); if (!strcmp(url, "/suggest") && reader != NULL) {
response = handle_suggest(connection,
httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
}
/* Specify the mime type */ /* Get static skin stuff */
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimeType.c_str()); else if (urlStr.substr(0, 6) == "/skin/") {
response = handle_skin(connection,
httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
} }
/* clear context pointer */ /* Display the search restults */
*ptr = NULL; else if (!strcmp(url, "/search")) {
response = handle_search(connection,
httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
}
/* Force to close the connection - cf. 100% CPU usage with v. 4.4 (in Lucid) */ /* Display a random article */
//MHD_add_response_header(response, MHD_HTTP_HEADER_CONNECTION, "close"); else if (!strcmp(url, "/random")) {
response = handle_random(connection,
httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
}
/* Allow cross-domain requests */ /* Display the content of a ZIM content (article, image, ...) */
//MHD_add_response_header(response, MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); else if (reader != NULL) {
MHD_add_response_header(response, "Access-Control-Allow-Origin", "*"); response = handle_content(connection,
httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
}
if (cacheEnabled) { /* Force cache */ /* Display the global Welcome page */
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, "max-age=2723040, public"); else {
} else { /* Prevent cache (for random page) */ response = handle_default(connection,
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, "no-cache, no-store, must-revalidate"); httpResponseCode,
reader,
searcher,
urlStr,
humanReadableBookId,
acceptEncodingDeflate);
} }
/* Queue the response */ /* Queue the response */

Loading…
Cancel
Save