size_t HTTPCURLRequest::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) { assert(userp); auto baton = reinterpret_cast<HTTPCURLRequest *>(userp); MBGL_VERIFY_THREAD(baton->tid); if (!baton->response) { baton->response = std::make_unique<Response>(); } const size_t length = size * nmemb; size_t begin = std::string::npos; if ((begin = headerMatches("last-modified: ", buffer, length)) != std::string::npos) { // Always overwrite the modification date; We might already have a value here from the // Date header, but this one is more accurate. const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n baton->response->modified = curl_getdate(value.c_str(), nullptr); } else if ((begin = headerMatches("etag: ", buffer, length)) != std::string::npos) { baton->response->etag = { buffer + begin, length - begin - 2 }; // remove \r\n } else if ((begin = headerMatches("cache-control: ", buffer, length)) != std::string::npos) { const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n baton->response->expires = parseCacheControl(value.c_str()); } else if ((begin = headerMatches("expires: ", buffer, length)) != std::string::npos) { const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n baton->response->expires = curl_getdate(value.c_str(), nullptr); } return length; }
void HTTPAndroidRequest::onResponse(JNIEnv* env, int code, jstring /* message */, jstring etag, jstring modified, jstring cacheControl, jstring expires, jbyteArray body) { response = std::make_unique<Response>(); using Error = Response::Error; if (etag != nullptr) { response->etag = mbgl::android::std_string_from_jstring(env, etag); } if (modified != nullptr) { response->modified = util::parseTimePoint(mbgl::android::std_string_from_jstring(env, modified).c_str()); } if (cacheControl != nullptr) { response->expires = parseCacheControl(mbgl::android::std_string_from_jstring(env, cacheControl).c_str()); } if (expires != nullptr) { response->expires = util::parseTimePoint(mbgl::android::std_string_from_jstring(env, expires).c_str()); } if (code == 200) { if (body != nullptr) { jbyte* bodyData = env->GetByteArrayElements(body, nullptr); response->data = std::make_shared<std::string>(reinterpret_cast<char*>(bodyData), env->GetArrayLength(body)); env->ReleaseByteArrayElements(body, bodyData, JNI_ABORT); } else { response->data = std::make_shared<std::string>(); } } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) { response->noContent = true; } else if (code == 304) { response->notModified = true; } else if (code == 404) { response->error = std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404"); } else if (code >= 500 && code < 600) { response->error = std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + std::to_string(code)); } else { response->error = std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + std::to_string(code)); } async.send(); }
void HTTPAndroidRequest::onResponse(int code, std::string message, std::string etag, std::string modified, std::string cacheControl, std::string expires, std::string body) { response = std::make_unique<Response>(); using Error = Response::Error; response->modified = parse_date(modified.c_str()); response->etag = etag; response->expires = parseCacheControl(cacheControl.c_str()); if (!expires.empty()) { response->expires = parse_date(expires.c_str()); } response->data = std::make_shared<std::string>(body); if (code == 200) { // Nothing to do; this is what we want } else if (code == 304) { if (existingResponse) { if (existingResponse->error) { response->error = std::make_unique<Error>(*existingResponse->error); } response->data = existingResponse->data; response->modified = existingResponse->modified; // We're not updating `expired`, it was probably set during the request. response->etag = existingResponse->etag; } else { // This is an unsolicited 304 response and should only happen on malfunctioning // HTTP servers. It likely doesn't include any data, but we don't have much options. } } else if (code == 404) { response->error = std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404"); } else if (code >= 500 && code < 600) { response->error = std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + std::to_string(code)); } else { response->error = std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + std::to_string(code)); } async.send(); }