|
@@ -37,7 +37,7 @@ IEspHttpException* createEspHttpException(int code, const char *_msg, const char
|
|
|
return new CEspHttpException(code, _msg, _httpstatus);
|
|
|
}
|
|
|
|
|
|
-bool httpContentFromFile(const char *filepath, StringBuffer &mimetype, MemoryBuffer &fileContents)
|
|
|
+bool httpContentFromFile(const char *filepath, StringBuffer &mimetype, MemoryBuffer &fileContents, bool &checkModifiedTime, StringBuffer &lastModified, StringBuffer &etag)
|
|
|
{
|
|
|
StringBuffer strfile(filepath);
|
|
|
|
|
@@ -49,6 +49,38 @@ bool httpContentFromFile(const char *filepath, StringBuffer &mimetype, MemoryBuf
|
|
|
Owned<IFile> file = createIFile(strfile.str());
|
|
|
if (file && file->isFile())
|
|
|
{
|
|
|
+ if (checkModifiedTime)
|
|
|
+ {
|
|
|
+ CDateTime createTime, accessedTime, modifiedTime;
|
|
|
+ file->getTime( &createTime, &modifiedTime, &accessedTime);
|
|
|
+ if ((lastModified.length() < 1) || (etag.length() > 0))
|
|
|
+ {
|
|
|
+ StringBuffer etagSource, etagForThisFile;
|
|
|
+ modifiedTime.getString(lastModified.clear());
|
|
|
+ etagSource.appendf("%s+%s", filepath, lastModified.str());
|
|
|
+ etagForThisFile.append(hashc((unsigned char *)etagSource.str(), etagSource.length(), 0));
|
|
|
+ if ( !streq(etagForThisFile.str(), etag.str()))
|
|
|
+ etag.set(etagForThisFile);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ checkModifiedTime = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ StringBuffer lastModifiedForThisFile;
|
|
|
+ modifiedTime.getString(lastModifiedForThisFile);
|
|
|
+ if ( !streq(lastModifiedForThisFile.str(), lastModified.str()))
|
|
|
+ lastModified.set(lastModifiedForThisFile);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ checkModifiedTime = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Owned<IFileIO> io = file->open(IFOread);
|
|
|
if (io)
|
|
|
{
|
|
@@ -2217,9 +2249,12 @@ int CHttpResponse::processHeaders(IMultiException *me)
|
|
|
|
|
|
bool CHttpResponse::httpContentFromFile(const char *filepath)
|
|
|
{
|
|
|
- StringBuffer mimetype;
|
|
|
+ StringBuffer mimetype, etag, lastModified;
|
|
|
MemoryBuffer content;
|
|
|
- bool ok = ::httpContentFromFile(filepath, mimetype, content);
|
|
|
+ //Set 'modified = false' here since this is called by CMySoapBinding::onGetFile() which does
|
|
|
+ //not need to check and set both 'etag' and 'lastModified' inside httpContentFromFile().
|
|
|
+ bool modified = false;
|
|
|
+ bool ok = ::httpContentFromFile(filepath, mimetype, content, modified, lastModified, etag);
|
|
|
if (ok)
|
|
|
{
|
|
|
setContent(content.length(), content.toByteArray());
|
|
@@ -2234,6 +2269,39 @@ bool CHttpResponse::httpContentFromFile(const char *filepath)
|
|
|
return ok;
|
|
|
}
|
|
|
|
|
|
+void CHttpResponse::setETageCacheControl(const char *etag, const char *contenttype)
|
|
|
+{
|
|
|
+ if (etag && *etag)
|
|
|
+ addHeader("Etag", etag);
|
|
|
+
|
|
|
+ if (!strncmp(contenttype, "image/", 6))
|
|
|
+ {
|
|
|
+ //if file being requested is an image file then set its expiration to a year
|
|
|
+ //so browser does not keep reloading it
|
|
|
+ addHeader("Cache-control", "max-age=31536000");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ addHeader("Cache-control", "max-age=300");
|
|
|
+}
|
|
|
+
|
|
|
+void CHttpResponse::setHTTPContent(bool modified, const char *lastmodified, const char *etag, const char *contenttype, MemoryBuffer &content)
|
|
|
+{
|
|
|
+ if (!modified)
|
|
|
+ {
|
|
|
+ if (etag && *etag)
|
|
|
+ setETageCacheControl(etag, contenttype);
|
|
|
+ setStatus(HTTP_STATUS_NOT_MODIFIED);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ addHeader("Last-Modified", lastmodified);
|
|
|
+ setETageCacheControl(etag, contenttype);
|
|
|
+ setContent(content.length(), content.toByteArray());
|
|
|
+ setContentType(contenttype);
|
|
|
+ setStatus(HTTP_STATUS_OK);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int CHttpResponse::receive(IMultiException *me)
|
|
|
{
|
|
|
// If it's receiving a response, it's behaving as the client side of this conversation.
|