Skip to content

Instantly share code, notes, and snippets.

Last active November 25, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stulentsev/3c15ad589797e471afc6 to your computer and use it in GitHub Desktop.
Save stulentsev/3c15ad589797e471afc6 to your computer and use it in GitHub Desktop.

Uploading files to TextMaster

TextMaster uses AWS S3 for storage, so s3-compatible libraries/toolkits can be used (for example, EvaporateJS). However, it is quite simple to do it with a basic HTTP client library, which is capable of doing GET/PUT requests.

The process consists of 4 steps:

  1. Obtain a file you want to upload
  2. Construct HTTP PUT request that will upload the file
  3. Obtain a signature for the upload request
  4. Send the signed request

1. Obtain a file

This is rather easy. Normally you'd have a filename and be able to read it. But in some environments (javascript/browser), user has to manually select it.

filename = '/path/to/example.txt'

2. Prepare parameters for the PUT request

Nothing extraordinary here. You need three parts: request uri, request body and request headers.

Request URI

path = 'api_uploads/5655a5a20ed4c0153d000000/example.txt'
#        ^ static  | ^ your document id     |  ^ filename to be used      
s3_uri = "{CGI.escape(path)}"
#                                      ^ url-escape 

Request body

This is where actual file content will be sent.

s3_params = {
  Key: 'example.txt',
  ContentType: 'text/plain',

Request headers

s3_headers = {
  'authorization' => authorization, # see below
  'x-amz-acl' => 'public-read', 
  'x-amz-date' =>, # => 'Wed, 25 Nov 2015 12:09:15 GMT'

3. Authorization / Signature

Value that you need to pass in "authorization" is a S3 REST API header and has this form:


To obtain the signature, you need to construct a correct string_to_sign and send it to Its construction is very thoroughly explained in S3 documentation. For this example, string to sign will look like this:

string_to_sign = "PUT


x-amz-date:Wed, 25 Nov 2015 12:09:15 GMT

Note the empty lines: first one is for missing Content-MD5 value (optional). The second one is for Date, which is overridden by x-amz-date header (some toolkits/libs won't let you set the Date header).

application/x-www-form-urlencoded is Content-Type of the request with which you will be sending file data. For multipart uploads it'll be multipart/form-data, naturally.

After you have this string, you send a GET to, passing string to sign in the to_sign parameter. As this endpoint is not publicly accessible, you will also need to provide a TextMaster API signature.

require 'rest_client'

signer_uri = ""

signer_headers = {
  # limitation of RestClient used in this example. This will be extracted and
  # sent as proper request parameters, not as a header value.
  params: { 
    to_sign: string_to_sign,
  apikey: '<TM api key>',
  date: 'Wed, 25 Nov 2015 12:09:15 GMT',
  signature: '<TM api signature>',

signature = RestClient::Request.execute(method: :get, 
                                        url: signer_uri,
                                        headers: signer_headers)

puts signature # 'Oe9O8iBUfUxUrbMNXoAKHfMwd5o='

4. Uploading the file, finally.

This is the simplest step:

RestClient.put s3_uri, s3_params, s3_headers

If you get back an HTTP 200 OK, then upload went successfully and your file is accessible at If you get back an HTTP 403 Forbidden, then your signature is invalid (most likely cause is string_to_sign being slightly incorrect).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment