Feature #8321 ยป 0001-WIP-WResource-sequences-and-setInvalidAfterChanged.patch
| src/Wt/WApplication.C | ||
|---|---|---|
|
sizes(aSizes), disabled(aDisabled)
|
||
|
{ }
|
||
|
WApplication::ExposedResourceInfo::ExposedResourceInfo(WResource* resource,
|
||
|
unsigned long sequence)
|
||
|
: resource(resource), sequence(sequence)
|
||
|
{ }
|
||
|
bool WApplication::ScriptLibrary::operator< (const ScriptLibrary& other) const
|
||
|
{
|
||
|
return uri < other.uri;
|
||
| ... | ... | |
|
std::string WApplication::addExposedResource(WResource *resource)
|
||
|
{
|
||
|
exposedResources_[resourceMapKey(resource)] = resource;
|
||
|
ExposedResourceInfo exposedResourceInfo(resource);
|
||
|
std::string key = resourceMapKey(resource);
|
||
|
ResourceMap::const_iterator i = exposedResources_.find(key);
|
||
|
if (i != exposedResources_.end())
|
||
|
exposedResourceInfo = i->second;
|
||
|
exposedResourceInfo.sequence++;
|
||
|
exposedResources_[key] = exposedResourceInfo;
|
||
|
std::string fn = resource->suggestedFileName().toUTF8();
|
||
|
if (!fn.empty() && fn[0] != '/')
|
||
|
fn = '/' + fn;
|
||
|
static unsigned long seq = 0;
|
||
|
if (resource->internalPath().empty())
|
||
|
return session_->mostRelativeUrl(fn)
|
||
|
+ "&request=resource&resource=" + Utils::urlEncode(resource->id())
|
||
|
+ "&rand=" + std::to_string(seq++);
|
||
|
+ "&rand=" + std::to_string(exposedResourceInfo.sequence);
|
||
|
else {
|
||
|
fn = resource->internalPath() + fn;
|
||
|
if (!session_->applicationName().empty() && fn[0] != '/')
|
||
| ... | ... | |
|
std::string key = resourceMapKey(resource);
|
||
|
ResourceMap::iterator i = exposedResources_.find(key);
|
||
|
if (i != exposedResources_.end() && i->second == resource) {
|
||
|
if (i != exposedResources_.end() && i->second.resource == resource) {
|
||
|
#ifndef WT_TARGET_JAVA
|
||
|
exposedResources_.erase(i);
|
||
|
#else
|
||
| ... | ... | |
|
ResourceMap::const_iterator i = exposedResources_.find(resourceKey);
|
||
|
|
||
|
if (i != exposedResources_.end())
|
||
|
return i->second;
|
||
|
return i->second.resource;
|
||
|
else {
|
||
|
std::size_t j = resourceKey.rfind('/');
|
||
|
if (j != std::string::npos && j > 1)
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
WResource *WApplication::decodeExposedResource(const std::string& resourceKey,
|
||
|
unsigned long rand) const
|
||
|
{
|
||
|
ResourceMap::const_iterator i = exposedResources_.find(resourceKey);
|
||
|
WResource *resource = nullptr;
|
||
|
if (i != exposedResources_.end())
|
||
|
resource = i->second.resource;
|
||
|
if (resource
|
||
|
&& resource->invalidAfterChanged()
|
||
|
&& (i->second.sequence != rand))
|
||
|
resource = nullptr;
|
||
|
return resource;
|
||
|
}
|
||
|
std::string WApplication::encodeObject(WObject *object)
|
||
|
{
|
||
|
std::string result = "w" + object->uniqueId();
|
||
| src/Wt/WApplication.h | ||
|---|---|---|
|
bool disabled;
|
||
|
};
|
||
|
struct ExposedResourceInfo {
|
||
|
ExposedResourceInfo(WResource* resource=nullptr, unsigned long sequence=0);
|
||
|
WResource* resource;
|
||
|
unsigned long sequence;
|
||
|
};
|
||
|
#ifndef WT_TARGET_JAVA
|
||
|
typedef std::map<std::string, EventSignalBase *> SignalMap;
|
||
|
typedef std::map<std::string, WResource *> ResourceMap;
|
||
|
typedef std::map<std::string, ExposedResourceInfo> ResourceMap;
|
||
|
#else
|
||
|
typedef std::weak_value_map<std::string, EventSignalBase *> SignalMap;
|
||
|
typedef std::weak_value_map<std::string, WResource *> ResourceMap;
|
||
|
typedef std::weak_value_map<std::string, ExposedResourceInfo> ResourceMap;
|
||
|
#endif
|
||
|
typedef std::map<std::string, WObject *> ObjectMap;
|
||
| ... | ... | |
|
std::string addExposedResource(WResource *resource);
|
||
|
bool removeExposedResource(WResource *resource);
|
||
|
WResource *decodeExposedResource(const std::string& resourceMapKey) const;
|
||
|
WResource *decodeExposedResource(const std::string& resourceMapKey,
|
||
|
unsigned long rand) const;
|
||
|
/*
|
||
|
* Methods for application state handling
|
||
| src/Wt/WResource.C | ||
|---|---|---|
|
WResource::WResource()
|
||
|
: trackUploadProgress_(false),
|
||
|
takesUpdateLock_(false),
|
||
|
invalidAfterChanged_(false),
|
||
|
dispositionType_(ContentDisposition::None),
|
||
|
app_(nullptr)
|
||
|
{
|
||
| ... | ... | |
|
dataChanged_.emit();
|
||
|
}
|
||
|
void WResource::setInvalidAfterChanged(bool enabled)
|
||
|
{
|
||
|
invalidAfterChanged_ = enabled;
|
||
|
}
|
||
|
const std::string& WResource::url() const
|
||
|
{
|
||
|
if (currentUrl_.empty())
|
||
| src/Wt/WResource.h | ||
|---|---|---|
|
*
|
||
|
* This does not work when the resource is deployed at an internal path using
|
||
|
* setInternalPath().
|
||
|
*
|
||
|
* \sa setInvalidAfterChanged()
|
||
|
*/
|
||
|
void setChanged();
|
||
|
/*! \brief Return "page not found" for prior resource URLs after change
|
||
|
*
|
||
|
* This option invalidates earlier versions of the resource url prior to
|
||
|
* the last call of setChanged().
|
||
|
*
|
||
|
* This does not work when the resource is deployed at an internal path using
|
||
|
* setInternalPath().
|
||
|
*
|
||
|
* \sa setChanged()
|
||
|
*/
|
||
|
void setInvalidAfterChanged(bool enabled);
|
||
|
/*! \brief Should "page not found" be returned for outdated resource URLs
|
||
|
*
|
||
|
* \sa setInvalidAfterChanged()
|
||
|
*/
|
||
|
bool invalidAfterChanged() const { return invalidAfterChanged_; }
|
||
|
/*! \brief Sets an internal path for this resource.
|
||
|
*
|
||
|
* Using this method you can deploy the resource at a fixed path. Unless
|
||
| ... | ... | |
|
bool trackUploadProgress_;
|
||
|
bool takesUpdateLock_;
|
||
|
bool invalidAfterChanged_;
|
||
|
std::vector<Http::ResponseContinuationPtr> continuations_;
|
||
| src/web/WebSession.C | ||
|---|---|---|
|
const std::string *resourceE = request.getParameter("resource");
|
||
|
const std::string *signalE = getSignal(request, "");
|
||
|
const std::string *randE = request.getParameter("rand");
|
||
|
if (signalE)
|
||
|
progressiveBoot_ = false;
|
||
| ... | ... | |
|
"<body> </body></html>";
|
||
|
handler.flushResponse();
|
||
|
} else {
|
||
|
if (!resource)
|
||
|
resource = app_->decodeExposedResource(*resourceE);
|
||
|
if (!resource) {
|
||
|
long rand = 0;
|
||
|
try {
|
||
|
if (randE)
|
||
|
rand = Utils::stol(*randE);
|
||
|
} catch (std::invalid_argument) {
|
||
|
rand = 0;
|
||
|
}
|
||
|
resource = app_->decodeExposedResource(*resourceE, rand);
|
||
|
}
|
||
|
if (resource) {
|
||
|
try {
|
||
| ... | ... | |
|
<< "' not exposed");
|
||
|
handler.response()->setContentType("text/html");
|
||
|
handler.response()->out() <<
|
||
|
"<html><body><h1>Nothing to say about that.</h1></body></html>";
|
||
|
"<html><body><h1>Page not found.</h1></body></html>";
|
||
|
handler.response()->setStatus(404);
|
||
|
handler.flushResponse();
|
||
|
}
|
||
|
}
|
||