You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@thrift.apache.org by Brian Hammond <br...@brianhammond.com> on 2009/04/03 04:45:45 UTC

Python server over HTTP, HTTPS -- How?

Hello,

I'm new to Thrift and have a general question about server deployment.

Part of my service requirement is similar to what EverNote is doing  
with their web service implementation. For a few reasons, they have  
decided to use HTTP as the transport (keep-alive, etc.).  Also, they  
don't want to send user credentials to the service without  
encryption.  So they've deployed their web service to support Thrift  
over HTTP and for the user-authentication part, over HTTPS.

 From the EverNote API docs at http://www.evernote.com/about/developer/api/evernote-api.htm 
  -

> Thrift represents the API as a set of structures and procedures on  
> the client, which marshal into binary messages that are transmitted  
> as HTTP requests.  Since HTTP is used as the low-level transport for  
> the EDAM messages over Thrift, these requests can take advantage of  
> standard HTTP tricks like keep-alive, load balancing, etc.

and

> The UserStore should always be accessed via SSL using a Thrift  
> TBinaryProtocol wrapping a THttpClient transport through the  
> following URL: <snip>

I'm assuming EverNote is running the PHP generated "server" since  
their staging/testing web service box is running Apache.

What I'm curious about is how I can do all of the following:

1) use SSL to encrypt user credentials
2) write my service implementation in python

I guess there's a few options for python but none completely solve  
both of these requirements.

1) use the Twisted python generator and run a daemon with twistd
2) deploy to nginx/apache with mod_wsgi and somehow hook-in support  
for decoding HTTP / HTTPS requests as Thrift RPCs.

In the first option I would have to run Twisted's webserver with SSL  
support.  This is different from the Twisted code generator solution  
which generates a standalone Twisted-based server.  Thus, I'm not sure  
how to continue with this option.

For the second option I am not sure there's the equivalent support in  
the python server code generator to do the equivalent of TPhpStream  
for python.  Again, I'm new to Thrift so maybe this option is not as  
hard as I think it is to setup.

Thoughts?

Thanks,
Brian

Re: Python server over HTTP, HTTPS -- How?

Posted by Terry Jones <te...@jon.es>.
>>>>> "Brian" == Brian Hammond <br...@brianhammond.com> writes:
Brian> I guess there's a few options for python but none completely solve
Brian> both of these requirements.

Brian> 1) use the Twisted python generator and run a daemon with twistd
Brian> 2) deploy to nginx/apache with mod_wsgi and somehow hook-in support  
Brian> for decoding HTTP / HTTPS requests as Thrift RPCs.

Brian> In the first option I would have to run Twisted's webserver with SSL
Brian> support.  This is different from the Twisted code generator solution
Brian> which generates a standalone Twisted-based server.  Thus, I'm not
Brian> sure how to continue with this option.

Hi Brian

If you use the Twisted Python generator it doesn't generate you a
standalone server.

On the server side it generates a class to handle the incoming requests,
provides some protocols and factories in thrift.transport.TTwisted (and, in
the contrib directory of txAMQP, you'll find code for Thrift-based AMQP
clients in case that's useful). It's left for you to decide how to hook
these things up.

So you can build a single Twisted plugin that talks plain TCP/IP or uses
SSL, etc. These interfaces can provide access to the same underlying
handler, or to two different handlers (one doing auth, one doing the more
mundane stuff). You can even use HTTP if you want to :-) You just create
(Thrift and) Twisted services, add them to a standard Twisted MultiService
and use twistd as the daemon process that launches the overall service.
That's all the standard Twisted approach to writing servers using their
plugin architecture (you can do the same with a tac file if you like).

Being also able to make Thrift calls transparently through AMQP is really
nice.  Among other things, it allows you to also add an AMQP client to your
outward-facing Twisted service (using the above-mentioned AMQP client code)
and then have its handler pass requests on to other (internal) services
listening on queues attached to an AMQP broker. The receiving services are
also Twisted AMQP clients, are also receiving method calls via txAMQP /
Thrift, are hooked up in exactly the same manner (as Twisted plugins), and
it all Just Works.

The real expert on this is Esteve Fernandez, who's also on this list. He's
away right now but will be back in action early next week. I'm just a happy
user of txAMQP - exactly as above.

Terry

Re: Python server over HTTP, HTTPS -- How?

Posted by Brian Hammond <br...@brianhammond.com>.
Hi Dave,

On Apr 2, 2009, at 10:55 PM, Dave Engberg wrote:

>
> Hey, Brian -
>
> I'm basically in charge of our API stuff (wrote the IDL, docs,  
> service implementation, etc.), and would be happy to chime in on any  
> questions you have.
>

Neat.  I figured you guys were on this list.

>
> Brian Hammond wrote:
>> I'm assuming EverNote is running the PHP generated "server" since  
>> their staging/testing web service box is running Apache.
> Our service implementation is Java on Tomcat, but some of our static  
> web pages run out of a PHP server for historic reasons.  All of the  
> Thrift goes through a single Java Servlet.  Originally, this servlet  
> was pretty small, and we could have given out the source, but now  
> it's all munged up with code for logging, throttling, etc.

Oh, Java. OK.

> The HTTP service basically needs to take the binary contents of the  
> HTTP POST and then hand them over to the server skeleton for  
> processing, and then marshal the results back into the binary  
> reply.  To correctly implement HTTP for portability, you need to  
> buffer the reply so you can give back a Content-Length header.
>
> The basic implementation is really simple if you're running on a  
> decent HTTP server, but you will need to add a decent amount of  
> exception handling to deal with all of the mess you get from  
> Internet connectivity if you're opening this up to the world.

OK.  I get it.  So I suppose if I were to open this up to the world  
I'd want to use nginx with mod_wsgi - it's very efficient.  Given  
that, I suppose I'd need to create the equivalent of TPhpStream,  
similar to what you did in your Java servlet.

I suppose I need to dig into the WSGI spec a bit deeper then but  
perhaps it's as simple as using the TBufferedTransport on the  
environ['wsgi.input'] ... Not sure yet if this is correct or not but  
this is encouraging: http://wsgi.org/wsgi/Specifications/handling_post_forms

> Currently environ['wsgi.input'] points to a stream that represents  
> the body of the HTTP request.

...

>> 1) use SSL to encrypt user credentials
> By using HTTP, we basically got HTTPS for free ... we offload it to  
> our Citrix load balancers, in fact, so our app servers just handle  
> HTTP.

Yeah, that's my thought exactly -- use HTTP and deploy to a solid  
httpd like nginx and you get all the heavy lifting for free, including  
epoll/poll/etc and HTTPS support.

OK, this is good.

Thanks!
Brian


Re: Python server over HTTP, HTTPS -- How?

Posted by Dave Engberg <de...@evernote.com>.
Hey, Brian -

I'm basically in charge of our API stuff (wrote the IDL, docs, service 
implementation, etc.), and would be happy to chime in on any questions 
you have.


Brian Hammond wrote:
> I'm assuming EverNote is running the PHP generated "server" since 
> their staging/testing web service box is running Apache.
Our service implementation is Java on Tomcat, but some of our static web 
pages run out of a PHP server for historic reasons.  All of the Thrift 
goes through a single Java Servlet.  Originally, this servlet was pretty 
small, and we could have given out the source, but now it's all munged 
up with code for logging, throttling, etc.

The HTTP service basically needs to take the binary contents of the HTTP 
POST and then hand them over to the server skeleton for processing, and 
then marshal the results back into the binary reply.  To correctly 
implement HTTP for portability, you need to buffer the reply so you can 
give back a Content-Length header.

The basic implementation is really simple if you're running on a decent 
HTTP server, but you will need to add a decent amount of exception 
handling to deal with all of the mess you get from Internet connectivity 
if you're opening this up to the world.


> 1) use SSL to encrypt user credentials
By using HTTP, we basically got HTTPS for free ... we offload it to our 
Citrix load balancers, in fact, so our app servers just handle HTTP.