fjolnir / HTTPKit

A minimal, high-performance Objective-C library to write self-sufficient web applications. Built on top of Mongoose.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to serve images

opened this issue · comments

Sorry for another ticket but couldn't find any documentation. How do you go about serving images?

The simplest way is just:

myHTTPServer.publicDir = <path to images>;

Then the server will serve them for you (unless you have a url handler that shadows the image url)

Other than that you can set the MIME type of a connection properly, and return an NSData object from your URL handler, however it is faster to let HTTPKit do it.

@fjolnir In my use case, the url's don't map directly to a filename so would have to go with the latter. Does using an NSData object mean the whole file is loaded into memory? If so is there any way to just return some kind of path object pointing to the file location?

I've added a method called -serveFile: to HTTPConnection.

[http handleGET:@"/file"
                   with:^id (HTTPConnection *connection) {
            [@"Hello!" writeToFile:@"/tmp/test.txt"
                        atomically:YES
                          encoding:NSUTF8StringEncoding
                             error:nil];
            [connection serveFileAtPath:@"/tmp/test.txt"];
            return nil;
        }];

You can only use this on fresh connections (Connections you have not written anything to already)
It handles the headers for you

@fjolnir Awesome, that's great.

Can you manually set a mime-type if required?

@fjolnir Another thing that could be useful is to set multiple public folders i.e. specify that /images/* should serve files from /my/custom/images/directory and /fonts/* should serve files from /another/directory. Technically doable with this solution but means that every request has to be handled manually.

If you want to map a directory to a wildcard, then you should be using publicDir

Regarding mime types, they are determined from file extension. I've added a hook so you can map additional extensions to mimetypes. (Example in main.m)

Sorry, I misread.
Yes it would be useful, but a much simpler way of doing that is to simply use symlinks in your filesystem :)

@fjolnir You can only set one public dir though... not sure how this would handle the scenario I mention i.e. serving /images/* from one directory and /fonts/* from another where both are not necessarily named in the same way as the urls.

Like being able to add custom mimetypes, great thanks. When I get using some of this stuff I'll look at committing documentation back to the project.

@fjolnir Our messages must have crossed. Symlinks are not an option in my use case so I'll just go with serving them manually. Thanks.

What is your use case?

@fjolnir A development environment where users control the file structure.

@fjolnir I may need to setup an HTTP proxy too, it this something HTTPKit can handle?

You mean you want HTTPKit to server requests from behind a proxy?
Or do you want it to act as a proxy?

@fjolnir To act as a proxy so that I can append stuff to the end of a file as it is served for example... Let's say there is a server running on port 8080, I want to run a proxy on 8081 for example that takes the response from 8080 and adjusts it before serving.

That's not directly supported.
But depending on what the proxy is to be used for, it should be fairly
trivial to make a request from within a handler and return the result.

What Sergey referred to is forward proxying.
You want "reverse". Which is much simpler to implement. But does not
really belong in HTTPKit (In my opinion anyway).

A naive implementation would look like:

[http handleGET:@"/proxy/**" with:^id (HTTPConnection *connection, NSArray *path) {
     NSString *forwardURLStr = [NSMutableString stringWithFormat:@"http://apple.com/%@", path];
     NSURL *forwardURL = [NSURL URLWithString:forwardURLStr];
     NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:forwardURL];

     NSHTTPURLResponse *response;
     NSData *responseData = [NSURLConnection sendSynchronousRequest:req
                                                  returningResponse:&response
                                                              error:nil];

     connection.shouldWriteHeaders = NO;
     NSDictionary *headers = [response allHeaderFields];
     [connection writeFormat:@"HTTP/1.1 %lu OK\r\n", [response statusCode]];
     for(NSString *header in headers) {
         if(![header isEqualToString:@"Content-Encoding"]
            && ![header isEqualToString:@"Content-Length"])
         [connection writeFormat:@"%@: %@\r\n", header, headers[header]];
     }
     [connection writeFormat:@"Content-Length: %lu\r\n\r\n", [responseData length]];
     [connection writeData:responseData];
     return nil;
}];

@fjolnir That's awesome. I had no idea that a reverse proxy was so simple. I guess thing get a little more complicated then handling post requests etc.

I would love to see your routing DSL running on top of CocoaHTTPServer. Given the change of the Mongoose licence, do you see this as a possible alternative going forward?