Fix bug where I.E9 could not access kiwix-serve content due to deflate.

This commit is contained in:
reg_ 2012-11-15 15:08:10 +00:00
parent 6d044853f4
commit 58fdb1d52f

View File

@ -24,16 +24,12 @@
#endif
#ifdef _WIN32
#if (_MSC_VER < 1600)
#include "stdint4win.h"
#endif
#include <winsock2.h>
#include <WS2tcpip.h> // otherwise socklen_t is not a recognized type
//#include <Windows.h> // otherwise int is not a recognized type
typedef int off_t;
#include <stdint4win.h>
#include <winsock2.h>
#include <Windows.h> // otherwise int is not a recognized type
typedef SSIZE_T ssize_t;
typedef UINT64 uint64_t;
typedef UINT16 uint16_t;
typedef int off_t;
extern "C" {
#include <microhttpd.h>
}
@ -126,9 +122,9 @@ string urlEncode(const string &c) {
void introduceTaskbar(string &content, const string &humanReadableBookId) {
pthread_mutex_lock(&resourceLock);
content = appendToFirstOccurence(content, "<head>", getResourceAsString("jqueryui/include.html.part"));
content = appendToFirstOccurence(content, "<head>", "<style>" +
content = appendToFirstOccurence(content, "<head>", "<style>" +
getResourceAsString("server/taskbar.css") + "</style>");
std::string HTMLDivRewrited = replaceRegex(getResourceAsString("server/taskbar.html.part"),
std::string HTMLDivRewrited = replaceRegex(getResourceAsString("server/taskbar.html.part"),
humanReadableBookId, "__CONTENT__");
content = appendToFirstOccurence(content, "<body[^>]*>", HTMLDivRewrited);
pthread_mutex_unlock(&resourceLock);
@ -146,7 +142,7 @@ bool isVerbose() {
/* For compression */
#define COMPRESSOR_BUFFER_SIZE 5000000
static Bytef *compr = (Bytef *)malloc(COMPRESSOR_BUFFER_SIZE);
static uLongf comprLen;
static uLongf comprLen;
static int accessHandlerCallback(void *cls,
struct MHD_Connection * connection,
@ -157,10 +153,15 @@ static int accessHandlerCallback(void *cls,
size_t * upload_data_size,
void ** ptr) {
/* Debug */
if (isVerbose()) {
std::cout << "Requesting " << url << std::endl;
}
/* Unexpected method */
if (0 != strcmp(method, "GET"))
return MHD_NO;
/* The first time only the headers are valid, do not respond in the first round... */
static int dummy;
if (&dummy != *ptr) {
@ -168,13 +169,8 @@ static int accessHandlerCallback(void *cls,
return MHD_YES;
}
/* Debug */
if (isVerbose()) {
std::cout << "Requesting (" << method << ") " << url << std::endl;
}
/* Check if the response can be compressed */
const string acceptEncodingHeaderValue = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_ENCODING) ?
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) : "";
const bool acceptEncodingDeflate = !acceptEncodingHeaderValue.empty() && acceptEncodingHeaderValue.find("deflate") != string::npos;
@ -203,9 +199,9 @@ static int accessHandlerCallback(void *cls,
}
pthread_mutex_lock(&mapLock);
kiwix::Searcher *searcher = searchers.find(humanReadableBookId) != searchers.end() ?
kiwix::Searcher *searcher = searchers.find(humanReadableBookId) != searchers.end() ?
searchers.find(humanReadableBookId)->second : NULL;
kiwix::Reader *reader = readers.find(humanReadableBookId) != readers.end() ?
kiwix::Reader *reader = readers.find(humanReadableBookId) != readers.end() ?
readers.find(humanReadableBookId)->second : NULL;
if (reader == NULL) {
humanReadableBookId="";
@ -225,7 +221,7 @@ static int accessHandlerCallback(void *cls,
if (isVerbose()) {
std::cout << "Searching suggestions for: \"" << term << "\"" << endl;
}
/* Get the suggestions */
content = "[";
reader->searchSuggestionsSmart(term, maxSuggestionCount);
@ -254,7 +250,7 @@ static int accessHandlerCallback(void *cls,
pattern = "";
/* Try first to load directly the article if exactly matching the pattern */
std::string patternCorrespondingUrl;
std::string patternCorrespondingUrl;
if (reader != NULL) {
pthread_mutex_lock(&readerLock);
reader->getPageUrlFromTitle(pattern, patternCorrespondingUrl);
@ -270,13 +266,13 @@ static int accessHandlerCallback(void *cls,
const char* end = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "end");
unsigned int startNumber = 0;
unsigned int endNumber = 25;
if (start != NULL)
startNumber = atoi(start);
if (end != NULL)
endNumber = atoi(end);
/* Get the results */
pthread_mutex_lock(&searcherLock);
try {
@ -287,21 +283,21 @@ static int accessHandlerCallback(void *cls,
std::cerr << e.what() << std::endl;
}
pthread_mutex_unlock(&searcherLock);
mimeType = "text/html; charset=utf-8";
} else {
content = "<html><head><title>Fulltext search unavailable</title></head><body><h1>Not Found</h1><p>There is no article with the title <b>\"" + string(pattern) + "\"</b> and the fulltext search engine is not available for this content.</p></body></html>";
mimeType = "text/html";
httpResponseCode = MHD_HTTP_NOT_FOUND;
}
}
}
/* Display the content of a ZIM article */
else if (reader != NULL) {
else if (reader != NULL) {
pthread_mutex_lock(&readerLock);
try {
found = reader->getContentByUrl(urlStr, content, contentLength, mimeType);
if (found) {
if (isVerbose()) {
cout << "Found " << urlStr << endl;
@ -311,7 +307,7 @@ static int accessHandlerCallback(void *cls,
} else {
if (isVerbose())
cout << "Failed to find " << urlStr << endl;
content = "<html><head><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";
httpResponseCode = MHD_HTTP_NOT_FOUND;
@ -325,9 +321,9 @@ static int accessHandlerCallback(void *cls,
if (mimeType.find("text/html") != string::npos) {
/* Special rewrite URL in case of ZIM file use intern *asbolute* url like /A/Kiwix */
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
"(href|src)(=[\"|\']/)([A-Z|\\-])/");
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
content = replaceRegex(content, "$1$2" + humanReadableBookId + "/$3/",
"(@import[ ]+)([\"|\']/)([A-Z|\\-])/");
}
}
@ -344,23 +340,30 @@ static int accessHandlerCallback(void *cls,
if (!humanReadableBookId.empty() && mimeType.find("text/html") != string::npos) {
introduceTaskbar(content, humanReadableBookId);
}
/* Compute the lengh */
contentLength = content.size();
/* Compress the content if necessary */
if (acceptEncodingDeflate && mimeType.find("text/html") != string::npos) {
pthread_mutex_lock(&compressorLock);
comprLen = COMPRESSOR_BUFFER_SIZE;
compress(compr, &comprLen, (const Bytef*)(content.data()), 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 */
compr++;
compr++;
content = string((char *)compr, comprLen);
contentLength = comprLen;
pthread_mutex_unlock(&compressorLock);
}
/* Create the response */
response = MHD_create_response_from_data(contentLength,
(void *)content.data(),
@ -375,8 +378,8 @@ static int accessHandlerCallback(void *cls,
/* Add if necessary the content-encoding */
if (acceptEncodingDeflate && mimeType.find("text/html") != string::npos) {
MHD_add_response_header(response, "Content-encoding", "deflate");
}
}
/* Specify the mime type */
MHD_add_response_header(response, "Content-Type", mimeType.c_str());
}
@ -421,7 +424,7 @@ int main(int argc, char **argv) {
{"port", required_argument, 0, 'p'},
{0, 0, 0, 0}
};
int option_index = 0;
int c = getopt_long(argc, argv, "dvli:a:p:", long_options, &option_index);
@ -431,7 +434,7 @@ int main(int argc, char **argv) {
case 'd':
daemonFlag = true;
break;
case 'v':
verboseFlag = true;
break;
@ -439,11 +442,11 @@ int main(int argc, char **argv) {
case 'l':
libraryFlag = true;
break;
case 'i':
indexPath = optarg;
break;
case 'p':
serverPort = atoi(optarg);
break;
@ -462,7 +465,7 @@ int main(int argc, char **argv) {
}
break;
}
}
/* Print usage)) if necessary */
@ -471,34 +474,32 @@ int main(int argc, char **argv) {
cerr << " kiwix-serve --library [--port=PORT] [--verbose] [--daemon] [--attachToProcess=PID] LIBRARY_PATH" << endl;
exit(1);
}
/* Setup the library manager and get the list of books */
if (libraryFlag) {
vector<string> libraryPaths = kiwix::split(libraryPath, ";");
vector<string> libraryPaths = kiwix::split(libraryPath, ":");
vector<string>::iterator itr;
for ( itr = libraryPaths.begin(); itr != libraryPaths.end(); ++itr ) {
if (!(*itr).empty()) {
bool retVal = false;
try {
retVal = libraryManager.readFile(*itr, true);
} catch (...) {
retVal = false;
}
if (!retVal) {
cerr << "Unable to open the XML library file '" << *itr << "'." << endl;
exit(1);
}
bool retVal = false;
try {
retVal = libraryManager.readFile(*itr, true);
} catch (...) {
retVal = false;
}
if (!retVal) {
cerr << "Unable to open the XML library file '" << *itr << "'." << endl;
exit(1);
}
}
/* Check if the library is not empty (or only remote books)*/
if (libraryManager.getBookCount(true, false)==0) {
cerr << "The XML library file '" << libraryPath << "' is empty (or has only remote books)." << endl;
cerr << "The XML library file '" << libraryPath << "' is empty (or has only remote books)." << endl;
}
} else {
if (!libraryManager.addBookFromPath(zimPath, zimPath, "", false)) {
cerr << "Unable to add the ZIM file '" << zimPath << "' to the internal library." << endl;
cerr << "Unable to add the ZIM file '" << zimPath << "' to the internal library." << endl;
exit(1);
} else if (!indexPath.empty()) {
vector<string> booksIds = libraryManager.getBooksIds();
@ -512,7 +513,7 @@ int main(int argc, char **argv) {
indexType = kiwix::XAPIAN;
} catch (...) {
}
#ifndef _WIN32
/* Try with the CluceneSearcher */
if (!hasSearchIndex) {
@ -520,12 +521,12 @@ int main(int argc, char **argv) {
new kiwix::CluceneSearcher(indexPath);
indexType = kiwix::CLUCENE;
} catch (...) {
cerr << "Unable to open the search index '" << indexPath << "' neither with the Xapian nor with CLucene." << endl;
cerr << "Unable to open the search index '" << indexPath << "' neither with the Xapian nor with CLucene." << endl;
exit(1);
}
}
#endif
libraryManager.setBookIndex(booksIds[0], indexPath, indexType);
}
}
@ -540,7 +541,7 @@ int main(int argc, char **argv) {
zimPath = currentBook.pathAbsolute;
if (!zimPath.empty()) {
indexPath = currentBook.indexPathAbsolute;
indexPath = currentBook.indexPathAbsolute;
/* Instanciate the ZIM file handler */
kiwix::Reader *reader = NULL;
@ -554,12 +555,12 @@ int main(int argc, char **argv) {
if (zimFileOk) {
string humanReadableId = currentBook.getHumanReadableIdFromPath();
readers[humanReadableId] = reader;
/* Instanciate the ZIM index (if necessary) */
kiwix::Searcher *searcher = NULL;
if (indexPath != "") {
bool hasSearchIndex = false;
/* Try to load the search */
try {
if (currentBook.indexType == kiwix::XAPIAN) {
@ -573,9 +574,9 @@ int main(int argc, char **argv) {
}
hasSearchIndex = true;
} catch (...) {
cerr << "Unable to open the search index '" << indexPath << "'." << endl;
cerr << "Unable to open the search index '" << indexPath << "'." << endl;
}
if (hasSearchIndex) {
searcher->setProtocolPrefix("/");
searcher->setSearchProtocolPrefix("/search?");
@ -613,8 +614,8 @@ int main(int argc, char **argv) {
/* Fork if necessary */
if (daemonFlag) {
pid_t pid;
/* Fork off the parent process */
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(1);
@ -645,7 +646,7 @@ int main(int argc, char **argv) {
&accessHandlerCallback,
page,
MHD_OPTION_END);
if (daemon == NULL) {
cerr << "Unable to instanciate the HTTP daemon. The port " << serverPort << " is maybe already occupied or need more permissions to be open. Please try as root or with a port number higher or equal to 1024." << endl;
exit(1);
@ -664,12 +665,12 @@ int main(int argc, char **argv) {
int mib[MIBSIZE];
struct kinfo_proc kp;
size_t len = sizeof(kp);
mib[0]=CTL_KERN;
mib[1]=KERN_PROC;
mib[2]=KERN_PROC_PID;
mib[3]=PPID;
int ret = sysctl(mib, MIBSIZE, &kp, &len, NULL, 0);
if (ret != -1 && len > 0) {
#else /* Linux & co */