In my opinion, it makes sense to throw a 404 when a non-existent Mura FW/1 plugin action is requested.
For example, if https://local.mysite.info/trainings/?calendaraction=main.thisActionIsBogus (referring to a plugin content object placed in a region) is requested, I'd like the site 404 to be rendered. I don't know a) if this is possible or b) how to implement it.
Here are some goofy experiments in the plugin's Application.cfc:
public any function onMissingView(any rc) {
var $ = rc.$;
// yields redirect loop
// application.serviceFactory.getBean('contentServer').render404();
/* yields:
* variable [OUT] doesn't exist at lucee.runtime.type.scope.UndefinedImpl.get(UndefinedImpl.java:226):226 at
* includes.fw1_cfc$cf.udfCall5(/var/www/vmhost/apps/mysite/cfml/deployment_root/wwwroot/plugins/calendar/includes/fw1.cfc:825):82
* ... */
//$.event('content', $.getBean('content').loadBy(filename='404'));
// yields: component [calendar.Application] has no function with name [doAction]
//getPageContext().forward("https://local.mysite.info/404/"));
// works, sort of, but not well: gives a 302, then the plugin-specific
// 404 view kicks in and returns 404
//redirect(action="public:errors.404"); // , queryString="template=json"
// yields: component [calendar.Application] has no function with name [doAction]
//getPageContext().forward("https://local.mysite.info/404/"));
}
Related
Rascal is currently hosting my simple web server. Here I have an input for users using HTML textarea tag, and a submit button. However, I can't figure out how to request that input data from users when they have submitted it. I also don't see much documentation about it, so any help would be appreciated!
Assuming you either use the Content and/or util::Webserver from the library for serving content from Rascal, you always provide a function of type Response (Request) to the server. This function does everything from serving index.html to receiving form inputs, and handling XMLHttpRequests. All you have to do is write the function's alternatives.
The kinds of Requests you can get are defined like this in Content.rsc:
data Request (map[str, str] headers = (), map[str, str] parameters = (), map[str,str] uploads = ())
= get (str path)
| put (str path, Body content)
| post(str path, Body content)
| delete(str path)
| head(str path)
;
And responses are defined by:
data Response
= response(Status status, str mimeType, map[str,str] header, str content)
| fileResponse(loc file, str mimeType, map[str,str] header)
| jsonResponse(Status status, map[str,str] header, value val, bool implicitConstructors = true, bool implicitNodes = true, str dateTimeFormat = "yyyy-MM-dd\'T\'HH:mm:ss\'Z\'")
;
In the example below I use convenience utility functions such as Content::response(str) which wrap an html string with the right HTTP status and mimetypes.
Example:
// this serves the initial form
Response myServer(get("/"))
= response("\<p\>What is your name?\</p\>
'\<form action=\"/submit\" method=\"GET\"\>
' \<input type=\"text\" name=\"name\" value=\"\"\>
'\</form\>
");
// // this responds to the form submission, now using a function body with a return (just for fun):
Response myServer(p:get("/submit")) {
return response("Hello <p.parameters["name"]>!");
}
// in case of failing to handle a request, we dump the request back for debugging purposes:
default Response myServer(Request q) = response("<q>");
Now we can serve this directly from the REPL. The content will show up in an Eclipse editor window or in your default browser and will stay available for 30 minutes after the last interaction in Rascal's internal application server:
rascal>content("test", myServer)
Serving 'test' at |http://localhost:9050/|
Or we can serve it on our own, then browse to http://localhost:10001 to test the server. We have to shut the thing down manually when we're done:
rascal>import util::Webserver;
ok
rascal>serve(|http://localhost:10001|, myServer)
ok
rascal>shutdown(|http://localhost:10001|)
The initially served page in an editor window
The response after for submission
Some email clients (apparently) encode the hash in a url to %23, (for example #/path#sectionId becomes #/path%23sectionId or %23/path%23sectionId).
When accessing such a url angular uses the otherwise propriety of $routeProvider and redirects you to your default page. (I think)
How could I decode the url before $routeProvider.when redirects you accordingly? Is there any work-around to this you are aware of? Ideally other than not using the hash to scroll to a section on the page.
Thanks.
A work around I found so far: adding a $location dependency to my main controller reveals that $location.hash return '' and $location.path returns '/path#sectionId'.
Based on this, we can add something like the following at the top of the controller:
// when has in url is encoded to %23, location.hash does not recognize it, and it gets cleared from the path in $RouteProvider
var holdHash = $location.path();
holdHash = holdHash.split('#');
if (holdHash.length > 1) { // if it has an item after the hash in the array
$location.hash(holdHash.pop()); //take that item and use it as a hash
}
BUT you lose the values in $location.search
OR you could do this:
$location.url(decodeURIComponent($location.url()))
which keeps your search too, but replaces '?' with '%3F' and then returns it in $location.ash not $location.search.
They are a tad hacky a solution somehow, and don't fully work (see problems with the $location.search)
***** EDIT 2 SOLUTION ****
As a final solution to my problem, I've updated the service that stored the id, and trigger the hash detection first thing in my main controller. Also updated the has detection to keep in mind all the variations in which that can be stored:
/**
* tries to get hash from $location
* if unavailable tries to look for encoded hash
* if unavailable returns null
* #return {string or null} [a string with the id of the section or null]
*/
function getHashID() {
var fromLoc = $location.hash(),
fromEncodedUrl,
inPath;
if (fromLoc.length) {
return fromLoc;
}
// iphone Chrome encodes the pound sign on redirect
fromEncodedUrl = $location.url();
fromEncodedUrl = fromEncodedUrl.split('%23');
if (fromEncodedUrl.length > 1) {
return fromEncodedUrl.pop();
}
inPath = $location.path();
inPath = inPath.split('#');
if (inPath.length > 1) {
return inPath.pop();
}
return null;
}
I later trigger the animation with the value stored in the service object, or getting a new value, and after the animation is done I clear the value in the service.
That's the signature for oneUrl function: oneUrl(route, url)
And from the documentation:
oneUrl(route, url): This will create a new Restangular object that is
just a pointer to one element with the specified URL.
To me, it seems useless to set Route when you are giving a url for the resource. Why does it exist in the argument list? Why is it mandatory? And how can it be used?
In my use of oneUrl I've found the route name is used to build the URL for subsequent PUT and DELETE operations. For example (pseudo code):
// "GET /api/v2/users/3/ HTTP/1.1" 200 184
var user = Restangular.oneUrl('myuser', 'http://localhost:8000/api/v2/users/3').get();
user.name = 'Fred';
// the following uses the route name and not the URL:
// "PUT /api/v2/myuser HTTP/1.1 404 100
user.put();
I was surprised by this behavior. I expected put() to use the same URL as get(); which would be helpful in my case.
My API uses absolute URLs within the JSON payloads to navigate to all related resources and I wanted to use oneUrl() to GET/PUT instances without recreating the routes in the JS code. But I'm pretty new to Restangular so I might not have the mental model correct.
www.foo.com/blog/posts/view/12/12/2013
There is no possible file corresponds to this request. So this URL needs to be parsed by some logic, or else you get a 404.
Since there is no corresponding file, the response cannot be automated by the server. I was just wondering which part of Cake FIRST responds to a request like this. I understand simple page requests are first parsed and resolved by the router. But the URL cannot just magically get to the front door of the router, right? I really want to know what is going on behind the scene that brings the URL to the router.
Check your app/webroot/index.php, the bottom:
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
new CakeRequest(),
new CakeResponse()
);
The key method of the Dispatcher is parseParams. This method gets triggered through the event system at the start of Dispatcher::dispatch(), checkt that method as well in the class.
What happens is basically that the dispatcher uses the router to parse the plain url and turns it into params and adds the parsed result to the request object and then dispatches a controller based on the parsed result.
/**
* Applies Routing and additionalParameters to the request to be dispatched.
* If Routes have not been loaded they will be loaded, and app/Config/routes.php will be run.
*
* #param CakeEvent $event containing the request, response and additional params
* #return void
*/
public function parseParams($event) {
$request = $event->data['request'];
Router::setRequestInfo($request);
$params = Router::parse($request->url);
$request->addParams($params);
if (!empty($event->data['additionalParams'])) {
$request->addParams($event->data['additionalParams']);
}
}
How can i deal with correct base url with wrong parameter?
Cakephp if u pass wrong controller or action name, it will lead to 404 page.
But if i enter correct controller/action name with wrong parameter, how can i deal with this kind of case.
Example:
correct: http://localhost/controller/action?params=123
wrong: http://localhost/controller/action?par23=123
par23 is wrong name. in this case i want to redirect to some pages like 404 page. is there any method or configuration i do not need to check parameter in controller and redirect to some page everytime.
thank you
You will need to check this manually in your controller.
Instead of looking for any extra wrong param, I would simply check if your needed params are there. If not, you can throw an exception.
This is how Cake's baked code does it:
// MyModelController.php
public function view($id = null) {
$this->MyModel->id = $id;
if (!$this->MyModel->exists()) {
throw new NotFoundException(__('Invalid thing'));
}
// ...
}
So here, an ID is needed. If it is not given (default value null) or no record with this Id exists, an Exception that results in a 404 is thrown.
Note that this has an extra benefit: It is not only covering the case where a param is missing, it also correctly returns an error if the param is present but references a non-existent item by $id.