functions_framework 0.9.0 → 0.10.0

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.
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