s33r 0.2 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. data/bin/s3cli.rb +25 -16
  2. data/html/classes/MIME.html +120 -0
  3. data/html/classes/MIME/InvalidContentType.html +119 -0
  4. data/html/classes/MIME/Type.html +1173 -0
  5. data/html/classes/MIME/Types.html +566 -0
  6. data/html/classes/Net.html +108 -0
  7. data/html/classes/Net/HTTPGenericRequest.html +233 -0
  8. data/html/classes/Net/HTTPResponse.html +242 -0
  9. data/html/classes/S33r.html +743 -0
  10. data/html/classes/S33r/BucketListing.html +372 -0
  11. data/html/classes/S33r/Client.html +981 -0
  12. data/html/classes/S33r/NamedBucket.html +620 -0
  13. data/html/classes/S33r/S33rException.html +118 -0
  14. data/html/classes/S33r/S33rException/BucketListingMaxKeysError.html +111 -0
  15. data/html/classes/S33r/S33rException/InvalidBucketListing.html +111 -0
  16. data/html/classes/S33r/S33rException/MalformedBucketName.html +111 -0
  17. data/html/classes/S33r/S33rException/MethodNotAvailable.html +111 -0
  18. data/html/classes/S33r/S33rException/MissingRequiredHeaders.html +111 -0
  19. data/html/classes/S33r/S33rException/MissingResource.html +111 -0
  20. data/html/classes/S33r/S33rException/UnsupportedCannedACL.html +111 -0
  21. data/html/classes/S33r/S33rException/UnsupportedHTTPMethod.html +111 -0
  22. data/html/classes/S33r/S3Object.html +307 -0
  23. data/html/classes/S33r/S3User.html +171 -0
  24. data/html/classes/S33r/Sync.html +151 -0
  25. data/html/classes/XML.html +200 -0
  26. data/html/classes/XML/Document.html +125 -0
  27. data/html/classes/XML/Node.html +124 -0
  28. data/html/created.rid +1 -0
  29. data/html/files/CHANGELOG.html +101 -0
  30. data/html/files/MIT-LICENSE.html +129 -0
  31. data/html/files/README_txt.html +209 -0
  32. data/html/files/lib/s33r/bucket_listing_rb.html +116 -0
  33. data/html/files/lib/s33r/client_rb.html +110 -0
  34. data/html/files/lib/s33r/core_rb.html +113 -0
  35. data/html/files/lib/s33r/libxml_extensions_rb.html +107 -0
  36. data/html/files/lib/s33r/mimetypes_rb.html +120 -0
  37. data/html/files/lib/s33r/named_bucket_rb.html +101 -0
  38. data/html/files/lib/s33r/s33r_exception_rb.html +101 -0
  39. data/html/files/lib/s33r/s33r_http_rb.html +108 -0
  40. data/html/files/lib/s33r/sync_rb.html +101 -0
  41. data/html/files/lib/s33r_rb.html +101 -0
  42. data/html/fr_class_index.html +52 -0
  43. data/html/fr_file_index.html +39 -0
  44. data/html/fr_method_index.html +126 -0
  45. data/html/index.html +24 -0
  46. data/html/rdoc-style.css +208 -0
  47. data/lib/s33r/bucket_listing.rb +69 -60
  48. data/lib/s33r/client.rb +150 -73
  49. data/lib/s33r/core.rb +56 -44
  50. data/lib/s33r/libxml_extensions.rb +10 -5
  51. data/lib/s33r/mimetypes.rb +3 -2
  52. data/lib/s33r/named_bucket.rb +89 -24
  53. data/lib/s33r/{s3_exception.rb → s33r_exception.rb} +2 -2
  54. data/lib/s33r/{net_http_overrides.rb → s33r_http.rb} +29 -21
  55. data/lib/s33r/sync.rb +4 -2
  56. data/test/cases/spec_bucket_listing.rb +10 -13
  57. data/test/cases/spec_client.rb +65 -0
  58. data/test/cases/spec_core.rb +16 -11
  59. data/test/cases/spec_namedbucket.rb +32 -0
  60. data/test/cases/spec_sync.rb +6 -5
  61. data/test/cases/spec_xml.rb +1 -1
  62. data/test/files/client_config.yml +6 -0
  63. data/test/files/namedbucket_config.yml +12 -0
  64. data/test/{s3_test_constants.rb → test_setup.rb} +7 -6
  65. metadata +63 -11
  66. data/LICENSE.txt +0 -22
  67. data/MIT-LICENSE +0 -21
  68. data/README.txt +0 -19
  69. data/bin/config.yml +0 -5
  70. data/test/cases/unit_client.rb +0 -40
  71. data/test/cases/unit_named_bucket.rb +0 -12
@@ -1,3 +1,14 @@
1
+ require 'base64'
2
+ require 'time'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'openssl'
6
+ require 'xml/libxml'
7
+
8
+ # Module to handle S3 operations which don't require an internet connection,
9
+ # i.e. data validation and request-building operations;
10
+ # also holds all the constants relating to S3.
11
+ #
1
12
  # Parts of this code are heavily based on Amazon's code. Here's their license:
2
13
  #
3
14
  # This software code is made available "AS IS" without warranties of any
@@ -8,35 +19,28 @@
8
19
  # Digital Services, Inc. or its affiliates with respect to your use of
9
20
  # this software code. (c) 2006 Amazon Digital Services, Inc. or its
10
21
  # affiliates.
11
-
12
- require 'base64'
13
- require 'time'
14
- require 'net/http'
15
- require 'net/https'
16
- require 'openssl'
17
- require 'xml/libxml'
18
-
19
- # this module handles operations which don't require an internet connection,
20
- # i.e. data validation and request building operations;
21
- # it also holds all the constants relating to S3
22
- module S3
22
+ module S33r
23
23
  HOST = 's3.amazonaws.com'
24
24
  PORT = 443
25
25
  NON_SSL_PORT = 80
26
26
  METADATA_PREFIX = 'x-amz-meta-'
27
+ # Size of each chunk (in bytes) to be sent per request when putting files.
28
+ DEFAULT_CHUNK_SIZE = 1048576
27
29
  AWS_HEADER_PREFIX = 'x-amz-'
28
30
  AWS_AUTH_HEADER_VALUE = "AWS %s:%s"
29
31
  INTERESTING_HEADERS = ['content-md5', 'content-type', 'date']
32
+ # Headers which must be included with every request to S3.
30
33
  REQUIRED_HEADERS = ['Content-Type', 'Date']
31
34
  CANNED_ACLS = ['private', 'public-read', 'public-read-write', 'authenticated-read']
35
+ # HTTP methods which S3 will respond to.
32
36
  METHOD_VERBS = ['GET', 'PUT', 'HEAD', 'POST', 'DELETE']
33
- # maximum number which can be passed in max-keys parameter when GETting bucket list
37
+ # Maximum number which can be passed in max-keys parameter when GETting bucket list.
34
38
  BUCKET_LIST_MAX_MAX_KEYS = 1000
35
- # default number of seconds an authenticated URL will last for (15 minutes)
39
+ # Default number of seconds an authenticated URL will last for (15 minutes).
36
40
  DEFAULT_EXPIRY_SECS = 60 * 15
37
41
 
38
- # builds the canonical string for signing;
39
- # modified (slightly) from the Amazon sample code
42
+ # Build canonical string for signing;
43
+ # modified (slightly) from the Amazon sample code.
40
44
  def generate_canonical_string(method, path, headers={}, expires=nil)
41
45
  interesting_headers = {}
42
46
  headers.each do |key, value|
@@ -77,14 +81,14 @@ module S3
77
81
  return buf
78
82
  end
79
83
 
80
- # get the header value for AWS authentication
84
+ # Get the value for the AWS authentication header.
81
85
  def generate_auth_header_value(method, path, headers, aws_access_key, aws_secret_access_key)
82
- raise S3Exception::MethodNotAvailable, "Method %s not available" % method if !METHOD_VERBS.include?(method)
86
+ raise S33rException::MethodNotAvailable, "Method %s not available" % method if !METHOD_VERBS.include?(method)
83
87
 
84
88
  # check the headers needed for authentication have been set
85
89
  missing_headers = REQUIRED_HEADERS - headers.keys
86
90
  if !(missing_headers.empty?)
87
- raise S3Exception::MissingRequiredHeaders,
91
+ raise S33rException::MissingRequiredHeaders,
88
92
  "Headers required for AWS auth value are missing: " + missing_headers.join(', ')
89
93
  end
90
94
 
@@ -94,24 +98,22 @@ module S3
94
98
  AWS_AUTH_HEADER_VALUE % [aws_access_key, signature]
95
99
  end
96
100
 
97
- # encode the given string with the aws_secret_access_key, by taking the
98
- # hmac sha1 sum, and then base64 encoding it
101
+ # Encode the given string with the aws_secret_access_key, by taking the
102
+ # hmac sha1 sum, and then base64 encoding it.
99
103
  def generate_signature(aws_secret_access_key, str)
100
104
  digest = OpenSSL::HMAC::digest(OpenSSL::Digest::Digest.new("SHA1"), aws_secret_access_key, str)
101
105
  Base64.encode64(digest).strip
102
106
  end
103
107
 
104
- # build the headers required with every S3 request
108
+ # Build the headers required with every S3 request (Date and Content-Type);
105
109
  # options hash can contain extra header settings, as follows:
106
110
  # :date and :content_type are required headers, and set to defaults if not supplied
107
111
  def add_default_headers(headers, options={})
108
-
109
112
  # set the default headers required by AWS
110
113
  missing_headers = REQUIRED_HEADERS - headers.keys
111
114
 
112
115
  if missing_headers.include?('Content-Type')
113
- content_type = options[:content_type] || ''
114
- headers['Content-Type'] = content_type
116
+ headers['Content-Type'] = options[:content_type] || ''
115
117
  end
116
118
 
117
119
  if missing_headers.include?('Date')
@@ -122,8 +124,8 @@ module S3
122
124
  headers
123
125
  end
124
126
 
125
- # add metadata headers to the request, correctly prefixing them first
126
- # returns the headers with the metadata headers appended
127
+ # Add metadata headers, correctly prefixing them first.
128
+ # Returns headers with the metadata headers appended.
127
129
  def metadata_headers(headers, metadata={})
128
130
  unless metadata.empty?
129
131
  metadata.each { |key, value| headers[METADATA_PREFIX + key] = value }
@@ -131,36 +133,34 @@ module S3
131
133
  headers
132
134
  end
133
135
 
134
- # add a canned ACL setter
136
+ # Add a canned ACL setter header.
135
137
  def canned_acl_header(canned_acl, headers={})
136
138
  unless canned_acl.nil?
137
139
  unless CANNED_ACLS.include?(canned_acl)
138
- raise S3Exception::UnsupportedCannedACL, "The canned ACL #{canned_acl} is not supported"
140
+ raise S33rException::UnsupportedCannedACL, "The canned ACL #{canned_acl} is not supported"
139
141
  end
140
142
  headers[AWS_HEADER_PREFIX + 'acl'] = canned_acl
141
143
  end
142
144
  headers
143
145
  end
144
146
 
145
- # guess a file's mime type
146
- # NB if the mime_type for a file cannot be guessed, "text/plain" is used
147
+ # Guess a file's mime type.
148
+ # If the mime_type for a file cannot be guessed, "text/plain" is used.
147
149
  def guess_mime_type(file_name)
148
150
  mime_type = MIME::Types.type_for(file_name)[0]
149
- mime_type = MIME::Types['text/plain'][0] unless mime_type
151
+ mime_type ||= MIME::Types['text/plain'][0]
150
152
  mime_type
151
153
  end
152
154
 
153
- # ensure that a bucket_name is well-formed (no leading or trailing slash)
155
+ # Ensure that a bucket_name is well-formed (no leading or trailing slash).
154
156
  def bucket_name_valid?(bucket_name)
155
- if '/' == bucket_name[0,1]
156
- raise S3Exception::MalformedBucketName, "Bucket name cannot have a leading slash"
157
- elsif '/' == bucket_name[-1,1]
158
- raise S3Exception::MalformedBucketName, "Bucket name cannot have a trailing slash"
157
+ if ('/' == bucket_name[0,1] || '/' == bucket_name[-1,1])
158
+ raise S33rException::MalformedBucketName, "Bucket name cannot have a leading or trailing slash"
159
159
  end
160
160
  end
161
161
 
162
- # convert a hash of name/value pairs to querystring variables
163
- # names can be strings or symbols
162
+ # Convert a hash of name/value pairs to querystring variables.
163
+ # Name for a variable can be a string or symbol.
164
164
  def generate_querystring(pairs={})
165
165
  str = ''
166
166
  if pairs.size > 0
@@ -169,7 +169,9 @@ module S3
169
169
  str
170
170
  end
171
171
 
172
- # put / between args, but only if it's not already there
172
+ # Build URLs from fragments.
173
+ # Does similar job to File.join but puts forward slash between arguments
174
+ # (only if it's not already there).
173
175
  def url_join(*args)
174
176
  url_start = ''
175
177
  url_end = args.join('/')
@@ -185,14 +187,15 @@ module S3
185
187
  # replace any multiple forward slashes (except those in the scheme)
186
188
  url_end = url_end.gsub(/\/{2,}/, '/')
187
189
 
188
- return url_start + url_end
190
+ url_start + url_end
189
191
  end
190
192
 
191
- def s3_absolute_url(bucket_name, resource_key)
193
+ # The public URL for this key (which only works if public-read ACL is set).
194
+ def s3_public_url(bucket_name, resource_key)
192
195
  "http://" + HOST + '/' + bucket_name + '/' + resource_key
193
196
  end
194
197
 
195
- # generate a gettable URL for an S3 resource key which passes authentication in querystring
198
+ # Generate a get-able URL for an S3 resource key which passes authentication in querystring.
196
199
  # int expires: when the URL expires (seconds since the epoch)
197
200
  def s3_authenticated_url(aws_access_key, aws_secret_access_key, bucket_name, resource_key,
198
201
  expires)
@@ -204,6 +207,15 @@ module S3
204
207
  querystring = generate_querystring({ 'Signature' => signature, 'Expires' => expires,
205
208
  'AWSAccessKeyId' => aws_access_key })
206
209
 
207
- return s3_absolute_url(bucket_name, resource_key) + querystring
210
+ return s3_public_url(bucket_name, resource_key) + querystring
211
+ end
212
+
213
+ # Turn keys in a hash hsh into symbols.
214
+ # Returns a hash with 'symbolised' keys.
215
+ def S33r.keys_to_symbols(hsh)
216
+ symbolised = hsh.inject({}) do |symbolised, key_value|
217
+ symbolised.merge({key_value[0].to_sym => key_value[1]})
218
+ end
219
+ symbolised
208
220
  end
209
221
  end
@@ -1,8 +1,11 @@
1
- # convenience methods for libxml classes
1
+ # Convenience methods for libxml classes.
2
2
  module XML
3
- # find first matching element and return its content
4
- # xpath: XPath query
5
- # returns nil if no element matches xpath
3
+ # Find first matching element and return its content
4
+ # (intended for use as a mixed-in method for Document instances).
5
+ #
6
+ # +xpath+: XPath query to run against self.
7
+ #
8
+ # Returns nil if no element matches +xpath+.
6
9
  def xget(xpath)
7
10
  nodes = self.find(xpath).to_a
8
11
  if nodes.empty?
@@ -12,17 +15,19 @@ module XML
12
15
  end
13
16
  end
14
17
 
15
- # parse an XML string into an XML::Document instance
18
+ # Parse an XML string into an XML::Document instance.
16
19
  def XML.get_xml_doc(xml_str)
17
20
  parser = XML::Parser.new
18
21
  parser.string = xml_str
19
22
  parser.parse
20
23
  end
21
24
 
25
+ # Make custom methods accessible to Document class.
22
26
  class Document
23
27
  include XML
24
28
  end
25
29
 
30
+ # Make custom methods accessible to Node class.
26
31
  class Node
27
32
  include XML
28
33
  end
@@ -1,4 +1,5 @@
1
- #--
1
+ # TODO: clarify license
2
+ #
2
3
  # MIME::Types for Ruby
3
4
  # Version 1.15
4
5
  #
@@ -7,7 +8,7 @@
7
8
  # $Id: types.rb,v 1.4 2006/02/12 21:27:22 austin Exp $
8
9
  #
9
10
  # The ChangeLog contains all details on revisions.
10
- #++
11
+ #
11
12
 
12
13
  # The namespace for MIME applications, tools, and libraries.
13
14
  module MIME
@@ -1,52 +1,117 @@
1
- # TODO: provide access to metadata on the enclosed bucket_listing
1
+ #-- TODO: provide access to metadata on the enclosed bucket_listing
2
+ require File.join(File.dirname(__FILE__), 'client')
2
3
 
3
- module S3
4
- # a client for dealing with a single bucket
4
+ module S33r
5
+ # Wraps the S33r::Client class to make it more convenient for use with a single bucket.
5
6
  class NamedBucket < Client
6
- attr_accessor :bucket_name
7
+ attr_accessor :bucket_name, :strict, :public_contents, :dump_requests
8
+
9
+ # Initialize an instance from a config_file. The config. file can include a separate
10
+ # +options+ section specifying options specific to NamedBucket instances (see the initialize method
11
+ # for more details).
12
+ # Other options are as for S33r::Client.init.
13
+ def NamedBucket.init(config_file)
14
+ aws_access_key, aws_secret_access_key, options, _ = super.class.load_config(config_file)
15
+ NamedBucket.new(aws_access_key, aws_secret_access_key, options)
16
+ end
7
17
 
8
- # options available:
9
- # :public_contents => true: all items put into bucket are made public (can be overridden per request)
10
- # :strict => true: check whether the bucket exists before attempting to initialize
11
- def initialize(aws_access_key, aws_secret_access_key, bucket_name, options={}, &block)
12
- @bucket_name = bucket_name
18
+ # Initialize a NamedBucket instance.
19
+ #
20
+ # +options+ is a hash of options for this instance:
21
+ # * <tt>:default_bucket => 'xxxx'</tt>: name of the bucket this client is attached to.
22
+ # * <tt>:public_contents => true</tt>: all items put into bucket are made public (can be overridden per request).
23
+ # * <tt>:strict => true</tt>: check whether the bucket exists before attempting to initialize; initialization \
24
+ # fails if the bucket does not exist
25
+ def initialize(aws_access_key, aws_secret_access_key, options={}, &block)
26
+ super(aws_access_key, aws_secret_access_key, options)
27
+
28
+ @bucket_name = options[:default_bucket]
13
29
 
14
30
  # holds a BucketListing instance
15
31
  @bucket_listing = nil
16
32
 
17
33
  # all content should be created as public-read
18
- @client_headers.merge!(canned_acl_header('public-read')) if options[:public_contents]
19
-
20
- super(aws_access_key, aws_secret_access_key, options)
34
+ @public_contents = (true == options[:public_contents])
35
+ @client_headers.merge!(canned_acl_header('public-read')) if @public_contents
21
36
 
22
- if true == options[:strict]
23
- raise S3Exception::MissingResource unless bucket_exists?(bucket_name)
37
+ @strict = (true == options[:strict])
38
+ if ((@strict && !bucket_exists?(@bucket_name)) || @bucket_name.nil?)
39
+ raise S33rException::MissingResource, "The specified bucket name #{@bucket_name} does not exist or is invalid"
24
40
  end
41
+
42
+ yield self if block_given?
25
43
  end
26
-
27
- def metadata
28
- # TODO: get bucket metadata from the bucket_listing
44
+
45
+ # Are all objects added to this bucket made public by default?
46
+ def public_contents?
47
+ @public_contents
29
48
  end
30
-
31
- def contents
32
- # TODO: S3Object instances inside the bucket_listing
49
+
50
+ # Is this a strict bucket (i.e. the target bucket must exist on S3)?
51
+ def strict?
52
+ @strict
53
+ end
54
+
55
+ # Get a single object from a bucket as a blob.
56
+ def [](key)
57
+ get_resource(@bucket_name, key).body
33
58
  end
34
59
 
60
+ # Get a BucketListing instance for the content of this bucket.
35
61
  def listing
36
- # TODO: build a bucket_listing whose objects are associated with the bucket
37
- # and set the @bucket_listing instance variable
38
- list_bucket(@bucket_name)
62
+ _, @bucket_listing = list_bucket(@bucket_name)
63
+ @bucket_listing
64
+ end
65
+
66
+ # Get a pretty list of the keys in the bucket.
67
+ def keys
68
+ listing.pretty
69
+ end
70
+
71
+ # List content of the bucket, and attach each item to this bucket as it is yielded.
72
+ def each_item
73
+ listing.contents.each_value { |item| item.named_bucket = self; yield item }
74
+ end
75
+
76
+ # Does this bucket exist?
77
+ # Returns true if the bucket this NamedBucket is mapped to exists.
78
+ def exists?
79
+ bucket_exists?(@bucket_name)
39
80
  end
40
81
 
82
+ # Put a string into a key inside the bucket.
41
83
  def put_text(string, resource_key, headers={})
42
84
  super(string, @bucket_name, resource_key, headers)
43
85
  end
44
86
 
87
+ # Put a file into the bucket.
45
88
  def put_file(filename, resource_key=nil, headers={}, options={})
46
89
  super(filename, @bucket_name, resource_key, headers, options)
47
90
  end
48
91
 
49
- # expires: time in secs since the epoch when
92
+ # Put a generic resource (e.g. from a data stream) into the bucket.
93
+ def put_stream(data, resource_key, headers={})
94
+ put_resource(@bucket_name, resource_key, data, headers)
95
+ end
96
+
97
+ # Delete the bucket.
98
+ def delete(headers={}, options={})
99
+ delete_bucket(@bucket_name, headers, options)
100
+ end
101
+
102
+ # Delete an object from the bucket.
103
+ #
104
+ # Returns boolean (true = deletion worked OK).
105
+ def delete_key(resource_key, headers={})
106
+ response = delete_resource(@bucket_name, resource_key, headers)
107
+ listing
108
+ response.ok?
109
+ end
110
+
111
+ # Generate an authenticated URL (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/)
112
+ # for an object inside this bucket.
113
+ #
114
+ # +expires+: time in secs since the epoch when the link should become invalid.
50
115
  def s3_authenticated_url(resource_key, expires=(Time.now.to_i + DEFAULT_EXPIRY_SECS))
51
116
  super(@aws_access_key, @aws_secret_access_key, @bucket_name, resource_key, expires)
52
117
  end
@@ -1,5 +1,5 @@
1
- module S3
2
- module S3Exception
1
+ module S33r
2
+ module S33rException
3
3
 
4
4
  class MethodNotAvailable < Exception
5
5
  end
@@ -1,21 +1,22 @@
1
1
  require 'net/http'
2
2
 
3
- # overrides for the default Net::HTTP classes
3
+ # Addtions to the Net::HTTP classes
4
4
 
5
- # add some convenience functions for checking response status
5
+ # Adds some convenience functions for checking response status.
6
6
  class Net::HTTPResponse
7
7
  attr_accessor :success
8
+ attr_writer :body
8
9
 
9
10
  def ok?
10
11
  success
11
12
  end
12
13
 
13
14
  def success
14
- response.is_a?(Net::HTTPOK)
15
+ code == '200'
15
16
  end
16
17
 
17
18
  def not_found
18
- response.is_a?(Net::HTTPNotFound)
19
+ code = '404'
19
20
  end
20
21
 
21
22
  def to_s
@@ -23,13 +24,34 @@ class Net::HTTPResponse
23
24
  end
24
25
  end
25
26
 
26
- # modified to enable larger chunk sizes to be used
27
- # when streaming data from large files
27
+ # Modification of Net::HTTP base class to enable larger chunk sizes to be used
28
+ # when streaming data from large files.
29
+ #
30
+ # N.B. does _not_ alter the behaviour of this class unless you set chunk_size
31
+ # using the accessor.
28
32
  class Net::HTTPGenericRequest
33
+ # Size of chunks (in bytes) to send when streaming body data.
29
34
  attr_accessor :chunk_size
30
35
 
36
+ # Dump initial line and raw request headers (useful for visual debugging).
37
+ #
38
+ # Switch on request debugging by passing <tt>:dump_requests => true</tt> to S33r::Client
39
+ # constructor.
40
+ def to_s
41
+ str = "*******\n" +
42
+ "#{self.class::METHOD} #{@path} HTTP/1.1\n" +
43
+ "Host: #{S33r::HOST}\n"
44
+
45
+ self.each_capitalized do |key, value|
46
+ str += "#{key}: #{value}\n"
47
+ end
48
+ str += "*******\n\n"
49
+ str
50
+ end
51
+
31
52
  private
32
- def send_request_with_body_stream(sock, ver, path, f)
53
+ # Minor alterations to original source to enable variable chunk sizes.
54
+ def send_request_with_body_stream(sock, ver, path, f) # :doc:
33
55
  raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" unless content_length() or chunked?
34
56
  unless content_type()
35
57
  warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
@@ -48,18 +70,4 @@ class Net::HTTPGenericRequest
48
70
  end
49
71
  end
50
72
  end
51
- end
52
-
53
- class Net::HTTPRequest
54
- def to_s
55
- str = "*******\n" +
56
- "#{self.class::METHOD} #{@path} HTTP/1.1\n" +
57
- "Host: #{S3::HOST}\n"
58
-
59
- self.each_capitalized do |key, value|
60
- str += "#{key}: #{value}\n"
61
- end
62
- str += "*******\n\n"
63
- str
64
- end
65
73
  end