Showing posts with label projects. Show all posts
Showing posts with label projects. Show all posts

Monday, October 13, 2008

An Open Source Python HTTP Client

At Super Happy Dev House 27, I made significant progress on an open source library for making HTTP requests in Python. For the past few years I've been working with web services and APIs (SOAP, REST (wikipedia) - specifically AtomPub, etc.) and I wanted to create an HTTP library which is simple, clean, and precise. Python has a couple of great HTTP libraries already, but one of them is a bit too low level (httplib) and the other is too high level (urllib2).

For example, in httplib you call a method to send data as if you are writing to a file (httplib uses sockets, after all). Required HTTP headers like Content-Length are not calculated for you. You'll need to handle cookies and redirects on your own. On the plus side, you get full control of what is being sent. The higher level library, urllib2, is built on top of httplib. It adds some handy abstractions, like calculating the Content-Length, but it also has some limitations. I haven't yet been able to figure out how to perform a PUT or DELETE with urllib2.

When making HTTP calls to web services, there are often a large number of HTTP headers, URL parameters, and components to the request. Making a request feels like making a function call in most HTTP libraries. In the past, I've wrapped these functions with successive layers containing more and more function parameters. For example, in a request to send a photo and metadata to PicasaWeb, you need to include an Authorization token, Content-Type specifying a MIME-multipart request and the multipart boundary, and a multipart payload consisting of the Atom XML describing the photo and the photo's binary data. If you add in the the ability to specify other headers and URL parameters, your function call might look like this:
def post_photo(url, url_parameters, escape_parameters, 
photo_mime_type, photo_file_handle,
photo_file_size, metadata_xml,
metadata_mime_type, auth_token,
additional_http_headers)
...

# Sets the request's Host, port, and uri.
# Makes the request into a MIME multipart request,
# adjusts the Content-Type and recalculates
# Content-Length.
# Sets the Authorization header
post_photo('http://picasaweb.google.com/data/'
'feed/api/user/userID/albumid/albumID', None,
False, 'image/jpeg', photo_file, photo_size,
atom_xml, 'application/atom-xml',
client_login_token, None)
To use the above, you have to gather all of the information in one place, and make the function call. There are cases where you want a design like the above.

However, more and more I think of ways the program could be more cleanly structured if this information could be compartmentalized. This new library relies on an HttpRequest object which various parts of the program modify. Once all of the modifications have been applied, the fully constructed request is passed to an HttpClient which communicates with the server using httplib or urlfetch if you happen to be on Google App Engine. (Support for more HTTP libraries is certainly possible.)

The photo posting example from above could look something like this. Keep in mind that these steps could be carried out in a different order in different segments of code.
photo_post = HttpRequest(method='POST')
# Sets the Authorization header
client_login_token.modify_request(photo_post)
# Adds to the body and calculated Content-Length,
# sets the Content-Type.
photo_post.add_body_part(atom_xml,
'application/atom+xml')
# Makes the request into a MIME multipart request,
# adjusts the Content-Type and recalculates
# Content-Length.
photo_post.add_body_part(photo_file, 'image/jpeg',
photo_size)
# Sets the request's Host, port, and uri.
parse_uri('http://picasaweb.google.com/data/'
'feed/api/user/userID/albumid/albumID'
).modify_request(photo_post)
In fact, the above code could make up the body of the post_photo function described in the first code snippet.

I created an open source project for this and other small projects called sippycode (a play on sippy cup). This is a place where code can grow up.

Sunday, September 07, 2008

A Revived Project

q12 is back!

I'm slowly starting back up again on my note taking wiki application. I created my own version of TiddlyWiki several months ago, but then started working on other projects. I'm planning to rewrite my note taking Ajax application to run on Google App Engine, and as I was getting started I realized that there were a few things missing from the Ajax library that I had written as part of this project.

I had created my own simple unit test framework in JavaScript, and I finally got around to uploading the unit tests for the library to the open source project. I've also been learning about manipulating browser cookies from within JavaScript. Aside: Cookie's in JavaScript are weird! When you say document.cookie = something, reading document.cookie doesn't give you the same thing back (the expiration, domain, and path information are squirreled away somewhere else).

I've also added a minified version of the q12 library, it weighs in at a mere 10k. Download the library today!

Wednesday, August 20, 2008

Dirt Simple CMS

I recently created an App Engine app to run www.jeffscudder.com. At the moment the code is extremely simple, and I get so few visitors to that web page that I doubt I will need anything complicated.

When I write blog posts and web pages, I have always preferred to just edit the HTML, and I have always wanted a simple content management system that just let me edit the HTML, JavaScript, CSS, ect. in the browser. Blogger comes awfully close to the perfect tool in my opinion, but it is geared towards displaying a series of posts. I wanted a landing page with links to all of the other content I put out there in the blagoweb. And I wanted to be able to host the simple web app's that I write (like the recently mentioned password generator).

With those design goals in mind, I set out to create my super simple content management system. It runs on App Engine, and the admin (me) is able to sign in to a special secret /content_manager page which lets me assign a specific blob of text to the desired URL under my domain. I can also set some basic metadata, like the content type (so that your browser knows how the content should be rendered) and cache control information, since HTTP caching is excellent and saves puppies from drowning in lakes (ok seriously it will alleviate congestion and unnecessary traffic when you want to give the same content to thousands or millions of people).

Editing pages through the /content_manager looks like this:




I've also decided to open source the code and I called the project scud-cms. Since App Engine is free for you to sign up, you can just upload this code and start setting your own content from right there in the browser.

(P.S. The idea for this simple content manager is very similar to one of my earlier projects: Scorpion Server, with which an authorized user could set the content at just about any URL they wanted.)

Sunday, November 04, 2007

JavaScript client for my Scorpion Server

I've added a JavaScript client to the simple web server project: scorpion server. The client is able to set the username and password and make authenticated GET and POST requests to retrieve and modify resources on the server. Now that this portion is complete, I'm ready to rebuild my Ajax Wiki application to run on top of this simple web server.

Thursday, October 18, 2007

Design for the simple secure storage server

In my last post, I mentioned my motivation for writing this server and pointed to the foundation I'm building on. Now it's time for more detail.

This server may not be supper fast (single thread execution) and it may not be super secure (user data stored in plaintext on the server) but it will be super easy to set up.

Allow me to clarify the security point in the above summary. In the initial version of this server, all traffic will be sent over an SSL connection (HTTPS) and users will authenticate with the server using Basic Auth. In Basic Auth, the users password is sent to the server in plaintext. There are better authentication schemes out there, but for this version of the server, I'm going for quick and simple. Basic Auth is just barely acceptable for this project because the connection is secure, but the server will likely store these passwords in plaintext as well (for now) so server disk security may be the weak link. With that said, the idea for this server is to provide a simple and portable back-end for my AJAX applications.

Thursday, October 11, 2007

A simple HTTPS server

Recently, I've been working on an AJAX application in my spare time and there's something I could really use: a simple network data store.

A JavaScript application isn't very useful without some persistent data. However this usually requires running a web server. My original idea was to distribute the application as a file which is loaded from the local disk. At this point you may be saying, "Wait a minute JavaScript running in a browser can't access the local disk." But scripts can read and write to the local disk if they are loaded from disk instead of the Internet. See TiddlyWiki for a great example of a useful application that uses this design. The problem though, is what happens when you want to sync the data from the AJAX application across multiple computers. Well, once again, it looks like I need a web server after all.

So I set out to build a simple server. All it really needs to do is allow applications to store and retrieve data. To make sure that the data remains a secret, the traffic will be sent over an HTTPS connection. Access to certain directories and files on the server will be granted only to select users, so usernames and passwords are required too. Since I've been working with Python recently, I tried to see if it was possible to create a simple HTTPS server which could handle GET and POST requests and perform dynamic behavior. I found a great example on activestate.com which uses an open SSL .pem file. The instructions in the article made setting up this server a breeze. I've been working on a customized version of the above example, but it isn't quite ready. As usual, stay tuned :)

Wednesday, July 18, 2007

New Domain and A New Project

A quick update on the domain name, I've registered jeffscudder.com and set up an email account, so you may be getting some mail from a new address the near future. I'm still looking for an idea on a domain to register for hosting projects. I'd like to get a name where my friends and I can all hook our email monikers (I don't imagine anyone wants to be bob@jeffscudder.com).

I've been working on a new project. I'm a huge fan of tiddlywiki, I've been using it almost a year now for keeping my notes organized. As I've continued to use it, I've found three things I would like to change:
  1. Contents are saved in plaintext. I carry my tiddlywiki around on a pen drive and some of the notes contain personal information that I'd like to keep safe. Plus, I like playing with cryptography.
  2. Notes are saved to a local file. This is both a strength and a weakness, the problem is I sometimes use multiple computers and I want to easily move between them. I'd like to have the option of saving to a local file or a server.
  3. It is sometimes slow. There is a lot of eye candy and it is very customizable, but I just want something lighweight, small, and simple.
I've gotten pretty far on my own wiki web app. but it's not quite ready to share. Keep an eye out for a release sometime in the near future.

I leave you with a song that has been stuck in my head all of last week: Deathbed by Relient K.