functions_framework 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a4d1e19c5565de4604964e48ff818b05460b2211ef2c8cfbd100bd572d802d7
4
- data.tar.gz: 380d987acf157075cfe7fca5bf038404eb800f48b80614ce9781f44cbd6de764
3
+ metadata.gz: aefd222f82f6f3b6e54e5a9fc512e20f3cad4ff9ac5dfe3ee454efbc4bf88f70
4
+ data.tar.gz: ba675682be6f79c8c799336c92551955ed6d2f24bcfa5ee17373cf75151897c1
5
5
  SHA512:
6
- metadata.gz: c76cb765863334411e7ab3bd448912fabc14c7725ae66465426ee996b05557d44653f64d47c98eb429d077f0df558b550b228a3fce014dd5aa9e02e4933cbc62
7
- data.tar.gz: af8d74d419c75dc8f850fa989d48780a26e2639045ff945d4b0a1cd29fa0085d3a82d058db6e49ed9c9f2c2855b3bc495a44ab530e129a846b24c111c76f79f2
6
+ metadata.gz: 937e27e64ad65f0f4fd9888c6bc94fcace25a39e68834f37c04d9aecb407b8fa0dc5ef35f8ebc1d78e0134914241e42cc92714f9d4236dee77daae5259cd55f1
7
+ data.tar.gz: 9eb7d77db1a3faae5ff91cc3c365383b96a02bbc78b7e733e9a85a8752decaf5e97b93ec78665af936840f56d89de7f542439adedef9c4a0b73912c4cc9a5748
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ### v0.10.0 / 2021-06-01
4
+
5
+ * ADDED: Support raw pubsub events sent by the pubsub emulator
6
+ * FIXED: Set proper response content-type charset when a function returns a string (plain text) or hash (JSON)
7
+ * FIXED: Properly handle conversion of non-ascii characters in legacy event strings
8
+
3
9
  ### v0.9.0 / 2021-03-18
4
10
 
5
11
  * BREAKING CHANGE: Servers are configured as single-threaded in production by default, matching the current behavior of Google Cloud Functions.
data/README.md CHANGED
@@ -60,7 +60,7 @@ Create a `Gemfile` listing the Functions Framework as a dependency:
60
60
  ```ruby
61
61
  # Gemfile
62
62
  source "https://rubygems.org"
63
- gem "functions_framework", "~> 0.9"
63
+ gem "functions_framework", "~> 0.10"
64
64
  ```
65
65
 
66
66
  Create a file called `app.rb` and include the following code. This defines a
data/docs/overview.md CHANGED
@@ -64,7 +64,7 @@ Create a `Gemfile` listing the Functions Framework as a dependency:
64
64
  ```ruby
65
65
  # Gemfile
66
66
  source "https://rubygems.org"
67
- gem "functions_framework", "~> 0.9"
67
+ gem "functions_framework", "~> 0.10"
68
68
  ```
69
69
 
70
70
  Create a file called `app.rb` and include the following code. This defines a
@@ -111,7 +111,7 @@ dependency on Sinatra in your `Gemfile`:
111
111
 
112
112
  ```ruby
113
113
  source "https://rubygems.org"
114
- gem "functions_framework", "~> 0.9"
114
+ gem "functions_framework", "~> 0.10"
115
115
  gem "sinatra", "~> 2.0"
116
116
  ```
117
117
 
@@ -470,7 +470,7 @@ Following is a typical layout for a Functions Framework based project.
470
470
  ```ruby
471
471
  # Gemfile
472
472
  source "https://rubygems.org"
473
- gem "functions_framework", "~> 0.9"
473
+ gem "functions_framework", "~> 0.10"
474
474
  ```
475
475
 
476
476
  ```ruby
@@ -27,10 +27,11 @@ module FunctionsFramework
27
27
  # @return [nil] if the event format was not recognized.
28
28
  #
29
29
  def decode_rack_env env
30
- content_type = ::CloudEvents::ContentType.new env["CONTENT_TYPE"]
30
+ content_type = ::CloudEvents::ContentType.new env["CONTENT_TYPE"], default_charset: "utf-8"
31
31
  return nil unless content_type.media_type == "application" && content_type.subtype_base == "json"
32
32
  input = read_input_json env["rack.input"], content_type.charset
33
33
  return nil unless input
34
+ input = convert_raw_pubsub_event input, env if raw_pubsub_payload? input
34
35
  context = normalized_context input
35
36
  return nil unless context
36
37
  construct_cloud_event context, input["data"]
@@ -40,7 +41,7 @@ module FunctionsFramework
40
41
 
41
42
  def read_input_json input, charset
42
43
  input = input.read if input.respond_to? :read
43
- input = input.encode charset if charset
44
+ input.force_encoding charset if charset
44
45
  content = ::JSON.parse input
45
46
  content = nil unless content.is_a? ::Hash
46
47
  content
@@ -48,6 +49,37 @@ module FunctionsFramework
48
49
  nil
49
50
  end
50
51
 
52
+ def raw_pubsub_payload? input
53
+ return false if input.include?("context") || !input.include?("subscription")
54
+ message = input["message"]
55
+ message.is_a?(::Hash) && message.include?("data") && message.include?("messageId")
56
+ end
57
+
58
+ def convert_raw_pubsub_event input, env
59
+ message = input["message"]
60
+ path = "#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
61
+ path_match = %r{projects/[^/?]+/topics/[^/?]+}.match path
62
+ topic = path_match ? path_match[0] : "UNKNOWN_PUBSUB_TOPIC"
63
+ timestamp = message["publishTime"] || ::Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%6NZ")
64
+ {
65
+ "context" => {
66
+ "eventId" => message["messageId"],
67
+ "timestamp" => timestamp,
68
+ "eventType" => "google.pubsub.topic.publish",
69
+ "resource" => {
70
+ "service" => "pubsub.googleapis.com",
71
+ "type" => "type.googleapis.com/google.pubsub.v1.PubsubMessage",
72
+ "name" => topic
73
+ }
74
+ },
75
+ "data" => {
76
+ "@type" => "type.googleapis.com/google.pubsub.v1.PubsubMessage",
77
+ "data" => message["data"],
78
+ "attributes" => message["attributes"]
79
+ }
80
+ }
81
+ end
82
+
51
83
  def normalized_context input
52
84
  id = normalized_context_field input, "eventId"
53
85
  timestamp = normalized_context_field input, "timestamp"
@@ -346,9 +346,9 @@ module FunctionsFramework
346
346
  when ::Rack::Response
347
347
  response.finish
348
348
  when ::String
349
- string_response response, "text/plain", 200
349
+ string_response response, 200
350
350
  when ::Hash
351
- string_response ::JSON.dump(response), "application/json", 200
351
+ string_response ::JSON.dump(response), 200, content_type: "application/json"
352
352
  when ::CloudEvents::CloudEventsError
353
353
  cloud_events_error_response response
354
354
  when ::StandardError
@@ -359,10 +359,17 @@ module FunctionsFramework
359
359
  end
360
360
 
361
361
  def notfound_response
362
- string_response "Not found", "text/plain", 404
362
+ string_response "Not found", 404
363
363
  end
364
364
 
365
- def string_response string, content_type, status
365
+ def string_response string, status, content_type: nil
366
+ string.force_encoding ::Encoding::ASCII_8BIT unless string.valid_encoding?
367
+ if string.encoding == ::Encoding::ASCII_8BIT
368
+ content_type ||= "application/octet-stream"
369
+ else
370
+ content_type ||= "text/plain"
371
+ content_type = "#{content_type}; charset=#{string.encoding.name.downcase}"
372
+ end
366
373
  headers = {
367
374
  "Content-Type" => content_type,
368
375
  "Content-Length" => string.bytesize
@@ -372,13 +379,13 @@ module FunctionsFramework
372
379
 
373
380
  def cloud_events_error_response error
374
381
  @config.logger.warn error
375
- string_response "#{error.class}: #{error.message}", "text/plain", 400
382
+ string_response "#{error.class}: #{error.message}", 400
376
383
  end
377
384
 
378
385
  def error_response message
379
386
  @config.logger.error message
380
387
  message = "Unexpected internal error" unless @config.show_error_details?
381
- string_response message, "text/plain", 500
388
+ string_response message, 500
382
389
  end
383
390
  end
384
391
 
@@ -330,20 +330,27 @@ module FunctionsFramework
330
330
  when ::Array
331
331
  ::Rack::Response.new response[2], response[0], response[1]
332
332
  when ::String
333
- string_response response, "text/plain", 200
333
+ string_response response, 200
334
334
  when ::Hash
335
335
  json = ::JSON.dump response
336
- string_response json, "application/json", 200
336
+ string_response json, 200, content_type: "application/json"
337
337
  when ::StandardError
338
338
  message = "#{response.class}: #{response.message}\n#{response.backtrace}\n"
339
- string_response message, "text/plain", 500
339
+ string_response message, 500
340
340
  else
341
341
  raise "Unexpected response type: #{response.inspect}"
342
342
  end
343
343
  end
344
344
 
345
345
  ## @private
346
- def string_response string, content_type, status
346
+ def string_response string, status, content_type: nil
347
+ string.force_encoding ::Encoding::ASCII_8BIT unless string.valid_encoding?
348
+ if string.encoding == ::Encoding::ASCII_8BIT
349
+ content_type ||= "application/octet-stream"
350
+ else
351
+ content_type ||= "text/plain"
352
+ content_type = "#{content_type}; charset=#{string.encoding.name.downcase}"
353
+ end
347
354
  headers = {
348
355
  "Content-Type" => content_type,
349
356
  "Content-Length" => string.bytesize
@@ -17,5 +17,5 @@ module FunctionsFramework
17
17
  # Version of the Ruby Functions Framework
18
18
  # @return [String]
19
19
  #
20
- VERSION = "0.9.0".freeze
20
+ VERSION = "0.10.0".freeze
21
21
  end
metadata CHANGED
@@ -1,43 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functions_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-18 00:00:00.000000000 Z
11
+ date: 2021-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cloud_events
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0.4'
20
+ - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: '0.1'
22
+ version: 2.a
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '0.4'
30
+ - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: '0.1'
32
+ version: 2.a
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: puma
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 4.3.0
40
+ - - "<"
32
41
  - !ruby/object:Gem::Version
33
- version: '4.3'
42
+ version: 6.a
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 4.3.0
50
+ - - "<"
39
51
  - !ruby/object:Gem::Version
40
- version: '4.3'
52
+ version: 6.a
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: rack
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -87,10 +99,10 @@ homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
87
99
  licenses:
88
100
  - Apache-2.0
89
101
  metadata:
90
- changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.9.0/file.CHANGELOG.html
102
+ changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.10.0/file.CHANGELOG.html
91
103
  source_code_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby
92
104
  bug_tracker_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues
93
- documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.9.0
105
+ documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.10.0
94
106
  post_install_message:
95
107
  rdoc_options: []
96
108
  require_paths:
@@ -106,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
118
  - !ruby/object:Gem::Version
107
119
  version: '0'
108
120
  requirements: []
109
- rubygems_version: 3.2.11
121
+ rubygems_version: 3.1.6
110
122
  signing_key:
111
123
  specification_version: 4
112
124
  summary: Functions Framework for Ruby