s33r 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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