I'm using AFHTTPClient to make requests to a Django+Tastypie app. This app has the APPEND_SLASH setting enabled, which means that if the URL doesn't end with a trailing slash, the request is redirected to the same URL with the slash appended.
Right now I'm doing this:
[[AFHTTPClient sharedClient] getPath:#"entry" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", error);
}];
The resulting URL is http://www.example.com/api/v1/entry, which gets redirected to http://www.example.com/api/v1/entry/. Is there any way to tell AFHTTPClient to always add a trailing slash automatically?
You need to either
Always provide the trailing / in your getPath: argument (like getPath:#"entry/"), or
Subclass AFHTTPClient with a method that adds it.
Here's an example of #2:
- (void)getPath:(NSString *)path
parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
if ([path length] > 0 && ![path hasSuffix:#"/"])
path = [path stringByAppendingString:#"/"];
[super getPath:path parameters:parameters success:success failure:failure];
}
Related
So I have a Jetty container with a URL like this: http://localhost:7071/my-app-name/ui/. The problem I'm running into is that Jetty seems to require that last trailing slash.
So this works:
http://localhost:7071/my-app-name/ui/
But this doesn't:
http://localhost:7071/my-app-name/ui
It's really weird, I would want the slash-less path to go to the same place as the path with a slash. That path is the homepage of the entire application, which is why I want it to work.
Here is some of my Jetty configuration.
PS. I'm working in Kotlin. The principles of how it works should still be the same though.
server = Server(props.getProperty(AppProps.PORT).toInt())
val handler = ServletContextHandler(server, root)
val appServletHolder = ServletHolder("AppServlet", AppServlet::class.java)
handler.addServlet(appServletHolder, "/ui/*")
handler.addEventListener(AppCore(props))
server.start()
I know I'm specifying "/ui/*" in my servlet holder configuration. But I can't seem to figure out any way to change that, I've tried a few combinations and none of them work better.
You've told the servlet spec that you want to listen on /ui/* so it mandates that your URLs must have the /ui/ portion.
But all is not lost, just tell the servlet spec the other url-patterns you are also interested in. (Servlets can be mapped to as many url-patterns as you want)
aka:
server = Server(props.getProperty(AppProps.PORT).toInt());
val handler = ServletContextHandler(server, root);
val appServletHolder = ServletHolder("AppServlet", AppServlet::class.java);
handler.addServlet(appServletHolder, "/ui"); // <-- like that
handler.addServlet(appServletHolder, "/ui/*");
handler.addEventListener(AppCore(props));
server.start();
Instead of adding a bunch of duplicate servlet mappings, I added one at the root to redirect any requests ending with "/" or "/index.html":
...
servletHandler.addServletWithMapping(RedirectServlet.class, "/*");
servletHandler.addServletWithMapping(AnotherServlet.class, "/ui");
...
public class RedirectServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String pathInfo = req.getPathInfo();
if(pathInfo.endsWith("/") || pathInfo.endsWith("/index.html")) {
String newPath = pathInfo.substring(0, pathInfo.lastIndexOf('/'));
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", newPath);
}
}
#Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp);
}
}
Is there a way to split url on varnish or change url structure with it.
I know regsub or regsuball support that but they are not enough in my case.
I would like to change a url and redirect it to another domain.
For example:
http://aaa.test.com/sport/99244-article-hyun-jun-suku-kapa.html?
to redirect below address
http://m.test.com/article-hyun-jun-suku-kapa-sport-99244/
I added some lines in vcl file to do that
set req.http.xrul=regsuball(req.url,".html",""); "clear .html"
set req.http.xrul=regsub(req.http.xrul,"(\d+)","\1"); find numbers --article ID =99244
I can rid of the article ID with
set req.http.xrul=regsub(req.http.xrul,"(\d+)","");
but cannot get just only article ID
set req.http.xrul=regsub(req.http.xrul,"(\d+)","\1"); or any other method
Does varnish support split the url with "-" pattern thus I could redesign the url? Or can we get only articleID with regsub?
Is this what you want to achieve?
set req.http.X-Redirect-URL = regsuball(req.url,"^/([^/]*)/([0-9]+)-([^/]+)\.html$","http://m.test.com/\3-\1-\2");
This is working code tailored to example you provided, just one level of section placement.
If you want to support more levels of sections, you only have to adjust regexp a bit and replace / to - in second step:
set req.http.X-Redirect-URL = "http://m.test.com/" + regsuball(regsuball(req.url, "^/(.*)/([0-9]+)-([^/]+)\.html$", "\3-\1-\2"), "/", "-");
Maybe you need one more refinement. What if URL doesn't match you pattern? X-Redirect-URL will be the very same value as req.url is. You definitely don't want redirect loop, so I suggest to add mark character to the begin of X-Redirect-URL and then test for it.
Let's say:
set req.http.X-Redirect-URL = regsuball(regsuball(req.url, "^/(.*)/([0-9]+)-([^/]+)\.html$", "#\3-\1-\2"), "/", "-");
if(req.http.X-Redirect-URL ~ "^#") {
set req.http.X-Redirect-URL = regsuball(req.http.X-Redirect-URL, "#", "http://m.test.com/");
return(synth(391));
} else {
unset req.http.X-Redirect-URL;
}
and for all cases, you need in vcl_synth:
if (resp.status == 391) {
set resp.status = 301;
set resp.http.Location = req.http.X-Redirect-URL;
return (deliver);
}
Hope this helps.
I have problem with specific redirect
My url is
http://example.com/test/some_file.jpg?refferer=mobile
And this must redirect to
http://example.com/parser.php?q=some_file.jpg
Normal redirect(without get params) i i've done by
rewrite test/(.*) /parser.php?q=$1 last;
location ~ ^/test/(.*)$ {
if ($arg_referrer = mobile) {
return 301 http://example.com/parser.php?q=$1;
}
# else ...
}
http://nginx.org/r/rewrite
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended.
So answer is really simple:
rewrite test/(.*) /parser.php?q=$1? last;
I have my site almost working. It works perfect with one language, but I have a cookie that sets the language. I hashed it also.
The problem is that I cant change the value of my cookie, I cant get an idea about how to do that.
My site receives a variable called "lg=1" where "1" is the language code.
I dont get the idea about how to pass that to my site, to get the "english" version and save the new cookie (with lg=1 value) again, so next time the user access without the lg=1 variable, he visits our english site, based on cookie value.
Can someody help me?
Thanky you
If you want to be able to set a cookie based on get-parameter you have two options
Set the cookie with javascript. Here is a SO answer for setting Cookie with JS
Configure Varnish to always pass requests containing "lg=" to your application so that you can set the cookie there.
sub vcl_recv {
if (req.url ~ ".*lg=") {
return (pass);
}
#Your other code in vcl_recv.....
}
You will probably need to edit your VCL file, by default something like /etc/varnish/default.vcl
When you receive a language parameter, you can set a cookie via Varnish.
Then use the value of the cookie to override the request url to the backend.
It should be something like that :
sub vcl_recv {
// Use the value of the cookie to override the request url.
if (req.http.Cookie ~ "lg") {
set req.url = req.url + "?" + req.http.Cookie;
}
// Go to VCL_error to redirect and remove the parametter.
if (req.url ~ "(?i)lg=1") {
error 802 "Remember to use the english version";
}
}
sub vcl_error {
/* Removes lg parameter and remember the english choice */
if (obj.status == 802) {
set obj.http.Set-Cookie = "lg=1; domain=." + req.http.host + "; path=/";
set obj.http.Location = req.http.X-Forwarded-Proto + "://" + req.http.host + regsub(req.url, "\?lg=1", "");
set obj.status = 302;
return(deliver);
}
}
I would prefer to use a different subdomain for each language, like that you can just redirect the user to the subdomain when you receive a parameter. By doing that you would not need to override the request.url each time.
I will use below approach to achieve:
Check lg cookie is exist or not. If not exist then set it using back-end server or varnish server.
I preferred to set language cookie using varnish instead of back-end server to avoid excessive request/load on back-end server.
Default language selection must be English i.e. "1"
Set the hash based on user language selection.It will help to maintain different cache based on language also retrieve the data from cache.
Please refer below code:
I have used IPD cookie.
backend default {
#applicable code goes here
}
sub identify_cookie{
#Call cookie based detection method in vcl_recv
if (req.http.cookie ~ "IPD=") {
set req.http.Language = regsub(req.http.cookie, "(.*?)(IPD=)([^;]*)(.*)$", "\3");
}
}
C{
#used to set persistent(9+ years) cookie from varnish server.
const char* persistent_cookie(char *cookie_name){
time_t rawtime;
struct tm *info;
char c_time_string[80];
rawtime = time(NULL) * 1.2; /*Added 9 years*/;
info = localtime(&rawtime);
strftime(c_time_string,80,"%a, %d-%b-%Y %H:%M:%S %Z", info);
char * new_str ;
if((new_str = malloc(strlen(cookie_name)+strlen(c_time_string)+1)) != NULL){
new_str[0] = '\0'; // ensures the memory is an empty string
strcat(new_str,cookie_name);
strcat(new_str,c_time_string);
} else {
syslog(LOG_INFO,"Persistent cookie malloc failed!\n");
}
return new_str;
}
}C
sub vcl_recv {
call identify_cookie; #Used to get identify cookie and get its value
if(!req.http.Cookie ~ "IPD"){
C{
VRT_SetHdr(sp, HDR_REQ, "\006X-IPD:",persistent_cookie("IPD=1; domain=yourdomain.com; path=/; Expires="),vrt_magic_string_end);
}C
}
}
sub vcl_fetch {
set beresp.http.Set-Cookie = req.http.X-IPD; #used for debug purpose only.Check cookie in response header
}
sub vcl_backend_response {
#applicable code goes here
}
sub vcl_deliver {
#applicable code goes here
set resp.http.X-Cookie = "Cookies Set ("req.http.X-IPD")"; #used for debug purpose only.Check cookie in response header
}
sub vcl_error {
#applicable code goes here
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
}
if(!req.http.Language){
req.http.Language = 1 #default english language
}
hash_data(req.http.Language); # make different hash for different language to avoid cache clashing
return(hash);
}
sub vcl_pipe {
#applicable code goes here
}
sub vcl_pass {
#applicable code goes here
}
Note: Please ensure to change cookie name only.Regular expression supports to retrive cookie value from multiple cookies without considering its order
I am trying to cache an image retrieved from Flickr. In order to create a unique filename for the cached image, I use CFURLCreateStringByAddingPercentEscapes to percent escape the URL. Appending that to the cache directory, I get a URL with the embedded Flickr URL properly percent escaped; but when I try to cache the image using NSData writeToURL:options:error: I get "The operation couldn’t be completed. No such file or directory" - and it shows the file URL with the original, unescaped Flickr URL where the file name should be.
For example, I NSLog the URL as:
file://localhost/Users/rick/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/77C4A7AA-C386-4575-AD21-B4027D080408/Library/Caches/http%3A%2F%2Ffarm3.static.flickr.com%2F2887%2F9391679341_26643bcafa_b.jpg
but the error message shows
NSFilePath=/Users/rick/Library/Application Support/iPhone Simulator/6.1/Applications/77C4A7AA-C386-4575-AD21-B4027D080408/Library/Caches/http://farm3.static.flickr.com/2887/9391679341_26643bcafa_b.jpg
It's as if in the process of converting the URL to a file path, writeToURL is removing the percent escapes.
Is there a way to prevent this from happening, or do I just need to come up with another way to generate unique names based on the url?
Here's the relevant code:
NSURL *cacheDirectoryURL=[[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString *photoURLString= (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef)([self.photoURL absoluteString]),
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8));
if (photoURLString)
{
NSURL *cachedPhotoURL=[NSURL URLWithString:[[cacheDirectoryURL absoluteString] stringByAppendingString:photoURLString]];
NSData *photoData=[NSData dataWithContentsOfURL:cachedPhotoURL];
if (photoData)
{
UIImage *image=[UIImage imageWithData:photoData];
self.imageView.image=image;
[self setupScrollView]; // new image, need to adjust scroll view
} else {
dispatch_queue_t fetchQueue=dispatch_queue_create("photo downloader", NULL);
dispatch_async(fetchQueue, ^{
NSData *photoData=[NSData dataWithContentsOfURL:self.photoURL];
NSError *error;
if ([photoData writeToURL:cachedPhotoURL options:NSDataWritingAtomic error:&error])
{
NSLog(#"Cached photo");
} else {
NSLog(#"Failed to cache photo");
NSLog(#"%#",error);
}
});
}
}
Thanks in advance for your help!
The problem is that [NSURL URLWithString:...] parses the given string and interprets the
percent escapes. Generally, to create a URL for a file system path, fileURLWithPath:
should be used.
In your case, the following simple code should work:
NSURL *cachedPhotoURL = [cacheDirectoryURL URLByAppendingPathComponent:photoURLString]