savon-multipart 2.1.1 → 2.1.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.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE/Bug_report.md +35 -0
- data/.github/ISSUE_TEMPLATE/Feature_request.md +27 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/ci.yml +81 -0
- data/.github/workflows/gem_push.yml +22 -0
- data/.rubocop.yml +37 -0
- data/.rubocop_todo.yml +7 -0
- data/CHANGELOG.md +11 -2
- data/Gemfile +15 -5
- data/README.md +17 -6
- data/RELEASING.md +19 -0
- data/Rakefile +10 -5
- data/lib/savon/multipart/response.rb +56 -7
- data/lib/savon/multipart/version.rb +3 -1
- data/lib/savon-multipart.rb +2 -0
- data/savon-multipart.gemspec +21 -19
- data/spec/fixtures/response/multipart_expected.xml +1 -0
- data/spec/fixtures/response/not_multipart_expected.xml +1 -0
- data/spec/fixtures/response/simple_xop.txt +13 -0
- data/spec/savon/multipart/response_spec.rb +125 -0
- metadata +25 -31
- data/.travis.yml +0 -10
- data/spec/savon/soap/response_spec.rb +0 -83
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4473b669ad70af6dfa4371b373da602fe0a9e982b70e2813473506bdf5d28146
|
|
4
|
+
data.tar.gz: 3270f043522e840c94fc3b0ac7b419ccc35e98aa9071c4f63b04844425724fa6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: df2da88ea80eb1d39cbb091d2139f47552e7353938daf76a33534553676140608cf84b5e65fb41b6870c6dc4192e5104875f8c8c0a58947d0963f48979d01169
|
|
7
|
+
data.tar.gz: 336c526a3f42e0d03560aa29d4046ea62b0efa6eba3a0058abf74e90ae80a8ec6165411926ab68595615fd9348acb928ba0e30c02805c5db6a663e41f4123fbb
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a bug report
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Please don't delete this template or we'll close your issue -->
|
|
8
|
+
<!-- Before creating an issue, please ensure you are using the latest version of savon-multipart. -->
|
|
9
|
+
|
|
10
|
+
# Bug report
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
**Current behavior:**
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
**Expected behavior:**
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
**Steps to reproduce current behavior:**
|
|
20
|
+
|
|
21
|
+
<!-- The more of the following you can give us, the faster we can reproduce and fix it. -->
|
|
22
|
+
|
|
23
|
+
* Client setup and the operation call (the Ruby code you ran):
|
|
24
|
+
|
|
25
|
+
* The request XML built by the client (or just the part that's wrong):
|
|
26
|
+
|
|
27
|
+
* The response you got back (body, and for a transport issue the status and headers):
|
|
28
|
+
|
|
29
|
+
* The WSDL of the service, or a snippet of the operation involved:
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
**System information:**
|
|
33
|
+
|
|
34
|
+
* ruby version:
|
|
35
|
+
* savon-multipart version:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a new feature for savon-multipart
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Please don't delete this template or we'll close your issue -->
|
|
8
|
+
|
|
9
|
+
## Feature request
|
|
10
|
+
|
|
11
|
+
<!-- Issues which contain questions or support requests will be closed. -->
|
|
12
|
+
|
|
13
|
+
**Motivation for this feature:**
|
|
14
|
+
|
|
15
|
+
<!-- Please describe the use case or problem this would solve. -->
|
|
16
|
+
|
|
17
|
+
**Proposed implementation:**
|
|
18
|
+
|
|
19
|
+
<!-- Please describe at least one proposed implementation design. -->
|
|
20
|
+
|
|
21
|
+
**Would this introduce a breaking change?**
|
|
22
|
+
|
|
23
|
+
<!-- If yes, please describe the impact and a migration path for existing applications. -->
|
|
24
|
+
|
|
25
|
+
**Are you willing to work on this yourself?**
|
|
26
|
+
yes
|
|
27
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
**What kind of change is this?**
|
|
2
|
+
|
|
3
|
+
<!-- E.g. a bugfix, feature, refactoring, build change, etc… -->
|
|
4
|
+
|
|
5
|
+
**Did you add tests for your changes?**
|
|
6
|
+
|
|
7
|
+
<!-- Note that we won't merge your changes if you don't add tests -->
|
|
8
|
+
|
|
9
|
+
**Summary of changes**
|
|
10
|
+
|
|
11
|
+
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
|
|
12
|
+
<!-- Try to link to an open issue for more information. -->
|
|
13
|
+
|
|
14
|
+
**Other information**
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: Ruby
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read # checkout only, nothing else
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
audit:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
16
|
+
with:
|
|
17
|
+
persist-credentials: false
|
|
18
|
+
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
19
|
+
with:
|
|
20
|
+
ruby-version: "3.4"
|
|
21
|
+
bundler-cache: true
|
|
22
|
+
- name: Audit dependencies
|
|
23
|
+
run: bundle exec bundle-audit check --update
|
|
24
|
+
- name: Audit Ruby runtime
|
|
25
|
+
# CVE-2026-41316 is an ERB flaw fixed in Ruby 4.0.3 and not yet backported.
|
|
26
|
+
# Ignored on affected rubies only. See:
|
|
27
|
+
# https://www.ruby-lang.org/en/news/2026/04/21/erb-cve-2026-41316/
|
|
28
|
+
# https://github.com/advisories/GHSA-q339-8rmv-2mhv
|
|
29
|
+
run: |
|
|
30
|
+
ignore=""
|
|
31
|
+
if ruby -e 'exit 1 unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new("4.0.3")'; then
|
|
32
|
+
ignore="--ignore CVE-2026-41316"
|
|
33
|
+
fi
|
|
34
|
+
bundle exec ruby-audit check $ignore
|
|
35
|
+
|
|
36
|
+
zizmor:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
40
|
+
with:
|
|
41
|
+
persist-credentials: false
|
|
42
|
+
- name: Audit workflows
|
|
43
|
+
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
|
|
44
|
+
with:
|
|
45
|
+
advanced-security: false # fail the build on findings instead of uploading SARIF
|
|
46
|
+
|
|
47
|
+
lint:
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
51
|
+
with:
|
|
52
|
+
persist-credentials: false
|
|
53
|
+
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
54
|
+
with:
|
|
55
|
+
ruby-version: "3.4"
|
|
56
|
+
bundler-cache: true
|
|
57
|
+
- name: RuboCop
|
|
58
|
+
run: bundle exec rubocop --format github
|
|
59
|
+
|
|
60
|
+
test:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
strategy:
|
|
63
|
+
fail-fast: false
|
|
64
|
+
matrix:
|
|
65
|
+
ruby: ['3.0', 3.1, 3.2, 3.3, 3.4, '4.0', truffleruby, head, truffleruby-head]
|
|
66
|
+
# Head builds exist to surface upstream regressions early.
|
|
67
|
+
# They should not block the build.
|
|
68
|
+
continue-on-error: ${{ matrix.ruby == 'head' || matrix.ruby == 'truffleruby-head' }}
|
|
69
|
+
env:
|
|
70
|
+
RAILS_ENV: test
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
73
|
+
with:
|
|
74
|
+
persist-credentials: false
|
|
75
|
+
- name: Set up Ruby
|
|
76
|
+
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
77
|
+
with:
|
|
78
|
+
ruby-version: ${{ matrix.ruby }}
|
|
79
|
+
bundler-cache: true # bundle installs and caches dependencies
|
|
80
|
+
- name: Run tests
|
|
81
|
+
run: bundle exec rake --trace
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Push gem
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
jobs:
|
|
6
|
+
push:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
contents: write
|
|
11
|
+
environment: release
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
14
|
+
with:
|
|
15
|
+
persist-credentials: false
|
|
16
|
+
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: "3"
|
|
19
|
+
bundler-cache: false
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: bundle install
|
|
22
|
+
- uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
plugins:
|
|
4
|
+
- rubocop-rake
|
|
5
|
+
- rubocop-rspec
|
|
6
|
+
|
|
7
|
+
AllCops:
|
|
8
|
+
TargetRubyVersion: 3.0
|
|
9
|
+
SuggestExtensions: true
|
|
10
|
+
|
|
11
|
+
Gemspec/RequireMFA:
|
|
12
|
+
Enabled: true
|
|
13
|
+
|
|
14
|
+
Gemspec/RequiredRubyVersion:
|
|
15
|
+
Enabled: false
|
|
16
|
+
# Gemspec floors are intentionally low; raising them is a separate breaking-change decision.
|
|
17
|
+
|
|
18
|
+
Naming/FileName:
|
|
19
|
+
Exclude:
|
|
20
|
+
- "lib/savon-multipart.rb"
|
|
21
|
+
# Entry-point file matches the gem name; renaming it would break `require "savon-multipart"`.
|
|
22
|
+
|
|
23
|
+
Layout/FirstHashElementIndentation:
|
|
24
|
+
EnforcedStyle: consistent
|
|
25
|
+
|
|
26
|
+
Layout/HashAlignment:
|
|
27
|
+
EnforcedHashRocketStyle: table
|
|
28
|
+
|
|
29
|
+
RSpec/ContextWording:
|
|
30
|
+
Enabled: false
|
|
31
|
+
|
|
32
|
+
Style/BlockDelimiters:
|
|
33
|
+
EnforcedStyle: semantic
|
|
34
|
+
|
|
35
|
+
Style/HashSyntax:
|
|
36
|
+
EnforcedStyle: ruby19
|
|
37
|
+
EnforcedShorthandSyntax: never
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# using RuboCop version 1.86.2.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
## 2.1.
|
|
1
|
+
## 2.1.3 (2026-09-16)
|
|
2
2
|
|
|
3
|
-
*
|
|
3
|
+
* Fix `xop:Include` parts with percent-encoded Content-IDs not being replaced in the response. ([#21](https://github.com/savonrb/savon-multipart/pull/21))
|
|
4
|
+
|
|
5
|
+
## 2.1.2 (2022-01-20)
|
|
6
|
+
|
|
7
|
+
* Loosen dependency on `mail` gem. ([#23](https://github.com/savonrb/savon-multipart/pull/23))
|
|
8
|
+
* Add ability to flatten MTOM XOP parts back into the main XML document ([#17](https://github.com/savonrb/savon-multipart/pull/17))
|
|
9
|
+
|
|
10
|
+
## 2.1.1
|
|
11
|
+
|
|
12
|
+
* Improve detection of multipart content-type header.
|
|
4
13
|
|
|
5
14
|
## 2.1.0
|
|
6
15
|
|
data/Gemfile
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source 'https://rubygems.org'
|
|
2
4
|
gemspec
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
gem '
|
|
8
|
-
gem '
|
|
6
|
+
if RUBY_VERSION > '3.1'
|
|
7
|
+
# net-smtp, net-pop and net-imap were removed from ruby 3.1 standard gems. See: https://github.com/rails/rails/pull/42366
|
|
8
|
+
# Can drop when https://github.com/mikel/mail/pull/1439 is resolved
|
|
9
|
+
gem 'net-imap', require: false
|
|
10
|
+
gem 'net-pop', require: false
|
|
11
|
+
gem 'net-smtp', require: false
|
|
9
12
|
end
|
|
13
|
+
|
|
14
|
+
gem 'rubocop', '~> 1.86', '>= 1.86.2'
|
|
15
|
+
gem 'rubocop-rake', '~> 0.7.1'
|
|
16
|
+
gem 'rubocop-rspec', '~> 3.9'
|
|
17
|
+
|
|
18
|
+
gem 'bundler-audit', '~> 0.9.3', require: false
|
|
19
|
+
gem 'ruby_audit', '~> 3.1', require: false if RUBY_VERSION >= '3.1.0'
|
data/README.md
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
Savon Multipart
|
|
2
|
-
===============
|
|
1
|
+
# Savon Multipart
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
[](https://github.com/savonrb/savon-multipart/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/savon-multipart)
|
|
5
|
+
|
|
6
|
+
Adds multipart support (SOAP with Attachments) to [Savon](https://github.com/savonrb/savon).
|
|
6
7
|
|
|
7
8
|
Installation
|
|
8
9
|
------------
|
|
9
10
|
|
|
10
|
-
Savon Multipart is available through [Rubygems](
|
|
11
|
+
Savon Multipart is available through [Rubygems](https://rubygems.org/gems/savon-multipart) and can be installed via:
|
|
11
12
|
|
|
12
13
|
```
|
|
13
14
|
$ gem install savon-multipart
|
|
14
15
|
```
|
|
15
16
|
|
|
17
|
+
Or in your `Gemfile`:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'savon-multipart', '~> 2.1'
|
|
21
|
+
```
|
|
22
|
+
|
|
16
23
|
Usage
|
|
17
24
|
------------
|
|
18
25
|
|
|
19
|
-
Just require the gem 'savon-multipart', which automatically requires 'savon' as well:
|
|
26
|
+
Just require the gem 'savon-multipart', '~> 2.1', which automatically requires 'savon' as well:
|
|
20
27
|
|
|
21
28
|
```
|
|
22
29
|
require 'savon-multipart'
|
|
23
30
|
```
|
|
31
|
+
|
|
32
|
+
## Ruby support
|
|
33
|
+
|
|
34
|
+
Savon Multipart requires Ruby >= 1.9.2.
|
data/RELEASING.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
_You'll need write access to the repository to create a release. Publishing is handled automatically via [trusted publishing](https://guides.rubygems.org/trusted-publishing/)._
|
|
2
|
+
|
|
3
|
+
## Cutting a release
|
|
4
|
+
|
|
5
|
+
1. On your release branch (e.g. `main`, `v2.x`), edit [CHANGELOG.md](https://github.com/savonrb/savon-multipart/blob/main/CHANGELOG.md) to finalize the new version number and list of all changes.
|
|
6
|
+
2. Bump [version.rb](https://github.com/savonrb/savon-multipart/blob/main/lib/savon/multipart/version.rb) to the version you picked in previous step.
|
|
7
|
+
3. **Final check**: make sure all tests are green, and that `rake build` succeeds. If not, merge any fixes back to the release branch and go to step 1.
|
|
8
|
+
4. [Draft a new release](https://github.com/savonrb/savon-multipart/releases/new) on Github.
|
|
9
|
+
- In the "Choose a tag" field, type the version tag - e.g. `v2.12.1` - and select "Create new tag on publish".
|
|
10
|
+
- Use `v[version]` for the release title, and copy the changelog into the release notes.
|
|
11
|
+
- Click "Publish release". Github creates and pushes the tag, which triggers the release workflow.
|
|
12
|
+
5. Publishing to RubyGems.org is fully automated. The [Push gem workflow](https://github.com/savonrb/savon-multipart/actions/workflows/gem_push.yml) triggers on the published release and requires approval from a release manager via the `release` environment before credentials are issued. **Before approving**: confirm that CI is green on the release commit. Approve the deployment in the Actions UI and the gem will be built and pushed automatically.
|
|
13
|
+
|
|
14
|
+
## Updating minimum ruby version
|
|
15
|
+
|
|
16
|
+
- Update `required_ruby_version` in [savon-multipart.gemspec](https://github.com/savonrb/savon-multipart/blob/main/savon-multipart.gemspec)
|
|
17
|
+
- Update the test matrix in [ci.yml](https://github.com/savonrb/savon-multipart/blob/main/.github/workflows/ci.yml)
|
|
18
|
+
- Update [README](https://github.com/savonrb/savon-multipart/blob/main/README.md) with the correct support matrix
|
|
19
|
+
- Note the updated requirement in [CHANGELOG.md](https://github.com/savonrb/savon-multipart/blob/main/CHANGELOG.md)
|
data/Rakefile
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler'
|
|
2
4
|
Bundler::GemHelper.install_tasks
|
|
3
5
|
|
|
4
|
-
require
|
|
6
|
+
require 'rspec/core/rake_task'
|
|
5
7
|
|
|
6
8
|
RSpec::Core::RakeTask.new do |t|
|
|
7
|
-
t.rspec_opts = %w
|
|
9
|
+
t.rspec_opts = %w[-c]
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
task :
|
|
12
|
+
desc 'Run the spec suite'
|
|
13
|
+
task default: :spec
|
|
14
|
+
|
|
15
|
+
desc 'Run the spec suite'
|
|
16
|
+
task test: :spec
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'mail'
|
|
4
|
+
require 'cgi'
|
|
2
5
|
|
|
3
6
|
module Savon
|
|
4
7
|
module Multipart
|
|
8
|
+
# Savon::Response subclass that understands multipart/related SOAP
|
|
9
|
+
# responses, exposing MIME parts, attachments and XOP content.
|
|
5
10
|
class Response < Savon::Response
|
|
6
11
|
attr_reader :parts
|
|
7
12
|
|
|
@@ -20,31 +25,75 @@ module Savon
|
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def xml
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
return super unless multipart?
|
|
29
|
+
|
|
30
|
+
parse_body unless @has_parsed_body
|
|
31
|
+
multipart_xml
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def multipart_xml
|
|
37
|
+
if xop?
|
|
38
|
+
parse_xop unless @has_parsed_xop
|
|
39
|
+
@xop_body
|
|
26
40
|
else
|
|
27
|
-
|
|
41
|
+
@parts.first.body.to_s
|
|
28
42
|
end
|
|
29
43
|
end
|
|
30
44
|
|
|
31
|
-
private
|
|
32
45
|
def multipart?
|
|
33
46
|
!(http.headers['content-type'] =~ /^multipart/im).nil?
|
|
34
47
|
end
|
|
35
48
|
|
|
49
|
+
def xop?
|
|
50
|
+
if multipart?
|
|
51
|
+
parse_body unless @has_parsed_body
|
|
52
|
+
!(@parts.first.header['content-type'].to_s =~ %r{^application/xop\+xml}i).nil?
|
|
53
|
+
else
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
36
58
|
def boundary
|
|
37
59
|
return unless multipart?
|
|
60
|
+
|
|
38
61
|
@boundary ||= Mail::Field.new('content-type', http.headers['content-type']).parameters['boundary']
|
|
39
62
|
end
|
|
40
63
|
|
|
41
64
|
def parse_body
|
|
42
65
|
@parts = Mail::Part.new(
|
|
43
|
-
:
|
|
44
|
-
:
|
|
66
|
+
headers: http.headers,
|
|
67
|
+
body: http.body
|
|
45
68
|
).body.split!(boundary).parts
|
|
46
69
|
@has_parsed_body = true
|
|
47
70
|
end
|
|
71
|
+
|
|
72
|
+
def parse_xop
|
|
73
|
+
parsed = Nokogiri.XML(@parts.first.body.to_s)
|
|
74
|
+
xop_elements = parsed.xpath('//xop:Include', xop: 'http://www.w3.org/2004/08/xop/include')
|
|
75
|
+
|
|
76
|
+
if xop_elements.empty?
|
|
77
|
+
@xop_body = @parts.first.body.to_s
|
|
78
|
+
else
|
|
79
|
+
replace_xop_includes(xop_elements)
|
|
80
|
+
@xop_body = parsed.to_s
|
|
81
|
+
end
|
|
82
|
+
@has_parsed_xop = true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def replace_xop_includes(xop_elements)
|
|
86
|
+
xop_elements.each do |xop_element|
|
|
87
|
+
href = xop_element.attributes['href'].to_s
|
|
88
|
+
cid = CGI.unescape(href[4..])
|
|
89
|
+
data = find_part_by_cid(cid).body.to_s
|
|
90
|
+
xop_element.parent.content = Base64.encode64(data).chomp
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def find_part_by_cid(cid)
|
|
95
|
+
@parts.find { |part| part.header['content-id'].to_s == "<#{cid}>" }
|
|
96
|
+
end
|
|
48
97
|
end
|
|
49
98
|
end
|
|
50
99
|
end
|
data/lib/savon-multipart.rb
CHANGED
data/savon-multipart.gemspec
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
$:.unshift lib unless $:.include? lib
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
|
|
5
|
+
|
|
6
|
+
require 'savon/multipart/version'
|
|
5
7
|
|
|
6
8
|
Gem::Specification.new do |s|
|
|
7
|
-
s.name =
|
|
9
|
+
s.name = 'savon-multipart'
|
|
8
10
|
s.version = Savon::Multipart::VERSION
|
|
9
|
-
s.authors = [
|
|
10
|
-
s.email = [
|
|
11
|
-
s.homepage =
|
|
12
|
-
s.summary =
|
|
13
|
-
s.description =
|
|
11
|
+
s.authors = ['Martin Westin', 'Daniel Harrington']
|
|
12
|
+
s.email = ['martin@eimermusic.com', 'me@rubiii.com']
|
|
13
|
+
s.homepage = 'http://savonrb.com'
|
|
14
|
+
s.summary = 'Heavy metal Ruby SOAP client with multipart support'
|
|
15
|
+
s.description = 'Adds multipart support (SOAP with Attachments) to Savon'
|
|
16
|
+
# NOTE: this floor is intentionally conservative — CI starts at Ruby 3.0, but the gem likely
|
|
17
|
+
# still works on older Rubies. Don't raise it just to satisfy lint or match CI without evidence of breakage.
|
|
14
18
|
s.required_ruby_version = '>= 1.9.2'
|
|
15
19
|
|
|
16
|
-
s.
|
|
17
|
-
|
|
18
|
-
s.add_dependency "savon", "~> 2"
|
|
19
|
-
s.add_dependency "mail", "~> 2.5.4"
|
|
20
|
+
s.add_dependency 'mail', '~> 2'
|
|
21
|
+
s.add_dependency 'savon', '~> 2'
|
|
20
22
|
|
|
21
|
-
s.add_development_dependency
|
|
22
|
-
s.add_development_dependency
|
|
23
|
-
s.add_development_dependency
|
|
24
|
-
s.add_development_dependency
|
|
25
|
-
s.add_development_dependency "transpec"
|
|
23
|
+
s.add_development_dependency 'autotest'
|
|
24
|
+
s.add_development_dependency 'pry'
|
|
25
|
+
s.add_development_dependency 'rake'
|
|
26
|
+
s.add_development_dependency 'rspec'
|
|
26
27
|
|
|
27
28
|
s.files = `git ls-files`.split("\n")
|
|
28
|
-
s.require_path =
|
|
29
|
+
s.require_path = 'lib'
|
|
30
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
|
29
31
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:wsdl="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><ns1:TransactionID soapenv:actor="" soapenv:mustUnderstand="1" xsi:type="xsd:string" xmlns:ns1="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2">2011012713535811111111111</ns1:TransactionID></soapenv:Header><soapenv:Body><SubmitReq xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2"><MM7Version>5.3.0</MM7Version><SenderIdentification><VASPID>messaging</VASPID><VASID>ADM</VASID><SenderAddress><ShortCode>1111</ShortCode></SenderAddress></SenderIdentification><Recipients><To><Number>11111111111</Number></To></Recipients><ServiceCode>1</ServiceCode><MessageClass>Personal</MessageClass><ExpiryDate>2011-01-28T13:53:58Z</ExpiryDate><DeliveryReport>false</DeliveryReport><ReadReply>false</ReadReply><Priority>Normal</Priority><Subject>Test MMS via Savon</Subject><ChargedParty>Sender</ChargedParty><Content href="cid:attachment_1" allowAdaptations="true"/></SubmitReq></soapenv:Body></soapenv:Envelope>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:wsdl="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><ns1:TransactionID soapenv:actor="" soapenv:mustUnderstand="1" xsi:type="xsd:string" xmlns:ns1="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2">2011012713535811111111111</ns1:TransactionID></soapenv:Header><soapenv:Body><SubmitReq xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2"><MM7Version>5.3.0</MM7Version><SenderIdentification><VASPID>messaging</VASPID><VASID>ADM</VASID><SenderAddress><ShortCode>1111</ShortCode></SenderAddress></SenderIdentification><Recipients><To><Number>11111111111</Number></To></Recipients><ServiceCode>1</ServiceCode><MessageClass>Personal</MessageClass><ExpiryDate>2011-01-28T13:53:58Z</ExpiryDate><DeliveryReport>false</DeliveryReport><ReadReply>false</ReadReply><Priority>Normal</Priority><Subject>Test MMS via Savon</Subject><ChargedParty>Sender</ChargedParty><Content href="cid:attachment_1" allowAdaptations="true"/></SubmitReq></soapenv:Body></soapenv:Envelope>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
----==_mimepart_4d416ae62fd32_201a8043814c4724
|
|
2
|
+
Content-ID: <http://tempuri.org/0>
|
|
3
|
+
Content-Transfer-Encoding: 8bit
|
|
4
|
+
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
|
|
5
|
+
|
|
6
|
+
<?xml version="1.0" encoding="UTF-8"?><envelope ><header></header><body><BinaryData><xop:Include href="cid:http://tempuri.org/1/123456789" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></BinaryData></body></envelope>
|
|
7
|
+
----==_mimepart_4d416ae62fd32_201a8043814c4724
|
|
8
|
+
Content-ID: <http://tempuri.org/1/123456789>
|
|
9
|
+
Content-Transfer-Encoding: binary
|
|
10
|
+
Content-Type: application/octet-stream
|
|
11
|
+
|
|
12
|
+
BinaryDataGoesHere
|
|
13
|
+
----==_mimepart_4d416ae62fd32_201a8043814c4724--
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'savon-multipart'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Savon::Multipart::Response do
|
|
6
|
+
let(:multipart_content_type) do
|
|
7
|
+
'multipart/related; boundary="--==_mimepart_4d416ae62fd32_201a8043814c4724"; ' \
|
|
8
|
+
'charset=UTF-8; type="text/xml"'
|
|
9
|
+
end
|
|
10
|
+
let(:header) { { 'Content-Type' => multipart_content_type } }
|
|
11
|
+
let(:body) { File.read(path) }
|
|
12
|
+
let(:response) { soap_response(headers: header, body: body) }
|
|
13
|
+
|
|
14
|
+
def soap_response(options = {})
|
|
15
|
+
defaults = { code: 200, headers: {}, body: '' }
|
|
16
|
+
response = defaults.merge options
|
|
17
|
+
globals = {
|
|
18
|
+
multipart: true,
|
|
19
|
+
raise_errors: true,
|
|
20
|
+
convert_response_tags_to: ->(tag) { Savon::StringUtils.snakecase(tag).to_sym }
|
|
21
|
+
}
|
|
22
|
+
http = HTTPI::Response.new(response[:code], response[:headers], response[:body])
|
|
23
|
+
|
|
24
|
+
Savon::Multipart::Response.new(http, globals, {})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'multipart' do
|
|
28
|
+
let(:path) { File.expand_path('../../fixtures/response/multipart.txt', __dir__) }
|
|
29
|
+
|
|
30
|
+
it 'parses the SOAP envelope from the first MIME part' do
|
|
31
|
+
expected = File.expand_path('../../fixtures/response/multipart_expected.xml', __dir__)
|
|
32
|
+
expect(response.xml.strip).to eq(File.read(expected))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'exposes the top-level MIME parts' do
|
|
36
|
+
expect(response.parts.length).to eq(2)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'exposes nested MIME parts' do
|
|
40
|
+
expect(response.parts[1].parts.length).to eq(3)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'decodes attachment bodies' do
|
|
44
|
+
expect(response.parts[1].parts[2].body.decoded.strip).to eq('This is a test message from Github')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'returns the attachments' do
|
|
48
|
+
expect(response.attachments.size).to eq(1)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'only parses the SOAP body once' do
|
|
52
|
+
# Referencing `response` here builds it (parsing the body a first time)
|
|
53
|
+
# before the spy is installed, so no further parses may happen below.
|
|
54
|
+
allow(response).to receive(:parse_body).and_call_original
|
|
55
|
+
|
|
56
|
+
5.times do
|
|
57
|
+
response.attachments
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
expect(response).not_to have_received(:parse_body)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'simple multipart' do
|
|
65
|
+
let(:path) { File.expand_path('../../fixtures/response/simple_multipart.txt', __dir__) }
|
|
66
|
+
|
|
67
|
+
it 'returns a String from the #xml method' do
|
|
68
|
+
expect(response.xml.class).to eq(String)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'returns a Hash from the #body method' do
|
|
72
|
+
expect(response.body).to eq({ submit_req: true })
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'simple xop' do
|
|
77
|
+
let(:path) { File.expand_path('../../fixtures/response/simple_xop.txt', __dir__) }
|
|
78
|
+
|
|
79
|
+
it 'returns a String from the #xml method' do
|
|
80
|
+
expect(response.xml.class).to eq(String)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'returns a Hash from the #body method, include xop data' do
|
|
84
|
+
expect(response.body).to eq({ binary_data: Base64.encode64('BinaryDataGoesHere').chomp })
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe 'a multipart response with case sensitive headers' do
|
|
89
|
+
let(:multipart_content_type) do
|
|
90
|
+
'MuLtIpArT/rElAtEd; boundary="--==_mimepart_4d416ae62fd32_201a8043814c4724"; ' \
|
|
91
|
+
'charset=UTF-8; type="text/xml"'
|
|
92
|
+
end
|
|
93
|
+
let(:path) { File.expand_path('../../fixtures/response/simple_multipart.txt', __dir__) }
|
|
94
|
+
|
|
95
|
+
it 'does not care about upper or lowercase values for ContentType' do
|
|
96
|
+
expect(response.body).to eq({ submit_req: true })
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'not multipart' do
|
|
101
|
+
let(:path) { File.expand_path('../../fixtures/response/not_multipart.txt', __dir__) }
|
|
102
|
+
let(:header) { { 'Content-Type' => 'text/html; charset=utf-8' } }
|
|
103
|
+
|
|
104
|
+
it 'parses soap messages without attachments too' do
|
|
105
|
+
expected = File.expand_path('../../fixtures/response/not_multipart_expected.xml', __dir__)
|
|
106
|
+
expect(response.xml.chomp).to eq(File.read(expected))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'has no parts' do
|
|
110
|
+
expect(response.parts.size).to eq(0)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'has no attachments' do
|
|
114
|
+
expect(response.attachments.size).to eq(0)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context 'soap errors' do
|
|
119
|
+
let(:path) { File.expand_path('../../fixtures/response/soap_fault.txt', __dir__) }
|
|
120
|
+
|
|
121
|
+
it 'handles them correctly' do
|
|
122
|
+
expect { response }.to raise_error(Savon::SOAPFault, /The service cannot be found/)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
metadata
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: savon-multipart
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martin Westin
|
|
8
8
|
- Daniel Harrington
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
|
-
name:
|
|
14
|
+
name: mail
|
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
|
17
16
|
requirements:
|
|
18
17
|
- - "~>"
|
|
@@ -26,21 +25,21 @@ dependencies:
|
|
|
26
25
|
- !ruby/object:Gem::Version
|
|
27
26
|
version: '2'
|
|
28
27
|
- !ruby/object:Gem::Dependency
|
|
29
|
-
name:
|
|
28
|
+
name: savon
|
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
|
31
30
|
requirements:
|
|
32
31
|
- - "~>"
|
|
33
32
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: 2
|
|
33
|
+
version: '2'
|
|
35
34
|
type: :runtime
|
|
36
35
|
prerelease: false
|
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
37
|
requirements:
|
|
39
38
|
- - "~>"
|
|
40
39
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 2
|
|
40
|
+
version: '2'
|
|
42
41
|
- !ruby/object:Gem::Dependency
|
|
43
|
-
name:
|
|
42
|
+
name: autotest
|
|
44
43
|
requirement: !ruby/object:Gem::Requirement
|
|
45
44
|
requirements:
|
|
46
45
|
- - ">="
|
|
@@ -68,21 +67,7 @@ dependencies:
|
|
|
68
67
|
- !ruby/object:Gem::Version
|
|
69
68
|
version: '0'
|
|
70
69
|
- !ruby/object:Gem::Dependency
|
|
71
|
-
name:
|
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
|
73
|
-
requirements:
|
|
74
|
-
- - ">="
|
|
75
|
-
- !ruby/object:Gem::Version
|
|
76
|
-
version: '0'
|
|
77
|
-
type: :development
|
|
78
|
-
prerelease: false
|
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
-
requirements:
|
|
81
|
-
- - ">="
|
|
82
|
-
- !ruby/object:Gem::Version
|
|
83
|
-
version: '0'
|
|
84
|
-
- !ruby/object:Gem::Dependency
|
|
85
|
-
name: autotest
|
|
70
|
+
name: rake
|
|
86
71
|
requirement: !ruby/object:Gem::Requirement
|
|
87
72
|
requirements:
|
|
88
73
|
- - ">="
|
|
@@ -96,7 +81,7 @@ dependencies:
|
|
|
96
81
|
- !ruby/object:Gem::Version
|
|
97
82
|
version: '0'
|
|
98
83
|
- !ruby/object:Gem::Dependency
|
|
99
|
-
name:
|
|
84
|
+
name: rspec
|
|
100
85
|
requirement: !ruby/object:Gem::Requirement
|
|
101
86
|
requirements:
|
|
102
87
|
- - ">="
|
|
@@ -117,27 +102,38 @@ executables: []
|
|
|
117
102
|
extensions: []
|
|
118
103
|
extra_rdoc_files: []
|
|
119
104
|
files:
|
|
105
|
+
- ".github/ISSUE_TEMPLATE/Bug_report.md"
|
|
106
|
+
- ".github/ISSUE_TEMPLATE/Feature_request.md"
|
|
107
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
|
108
|
+
- ".github/dependabot.yml"
|
|
109
|
+
- ".github/workflows/ci.yml"
|
|
110
|
+
- ".github/workflows/gem_push.yml"
|
|
120
111
|
- ".gitignore"
|
|
121
112
|
- ".rspec"
|
|
122
|
-
- ".
|
|
113
|
+
- ".rubocop.yml"
|
|
114
|
+
- ".rubocop_todo.yml"
|
|
123
115
|
- CHANGELOG.md
|
|
124
116
|
- Gemfile
|
|
125
117
|
- LICENSE
|
|
126
118
|
- README.md
|
|
119
|
+
- RELEASING.md
|
|
127
120
|
- Rakefile
|
|
128
121
|
- lib/savon-multipart.rb
|
|
129
122
|
- lib/savon/multipart/response.rb
|
|
130
123
|
- lib/savon/multipart/version.rb
|
|
131
124
|
- savon-multipart.gemspec
|
|
132
125
|
- spec/fixtures/response/multipart.txt
|
|
126
|
+
- spec/fixtures/response/multipart_expected.xml
|
|
133
127
|
- spec/fixtures/response/not_multipart.txt
|
|
128
|
+
- spec/fixtures/response/not_multipart_expected.xml
|
|
134
129
|
- spec/fixtures/response/simple_multipart.txt
|
|
130
|
+
- spec/fixtures/response/simple_xop.txt
|
|
135
131
|
- spec/fixtures/response/soap_fault.txt
|
|
136
|
-
- spec/savon/
|
|
132
|
+
- spec/savon/multipart/response_spec.rb
|
|
137
133
|
homepage: http://savonrb.com
|
|
138
134
|
licenses: []
|
|
139
|
-
metadata:
|
|
140
|
-
|
|
135
|
+
metadata:
|
|
136
|
+
rubygems_mfa_required: 'true'
|
|
141
137
|
rdoc_options: []
|
|
142
138
|
require_paths:
|
|
143
139
|
- lib
|
|
@@ -152,9 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
152
148
|
- !ruby/object:Gem::Version
|
|
153
149
|
version: '0'
|
|
154
150
|
requirements: []
|
|
155
|
-
|
|
156
|
-
rubygems_version: 2.4.6
|
|
157
|
-
signing_key:
|
|
151
|
+
rubygems_version: 3.6.9
|
|
158
152
|
specification_version: 4
|
|
159
153
|
summary: Heavy metal Ruby SOAP client with multipart support
|
|
160
154
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
require 'savon-multipart'
|
|
2
|
-
|
|
3
|
-
describe Savon::Multipart::Response do
|
|
4
|
-
|
|
5
|
-
let(:header) {{ "Content-Type" => 'multipart/related; boundary="--==_mimepart_4d416ae62fd32_201a8043814c4724"; charset=UTF-8; type="text/xml"' }}
|
|
6
|
-
let(:body) { File.read(path) }
|
|
7
|
-
let(:response) { soap_response(:headers => header, :body => body) }
|
|
8
|
-
|
|
9
|
-
def soap_response(options = {})
|
|
10
|
-
defaults = { :code => 200, :headers => {}, :body => "" }
|
|
11
|
-
response = defaults.merge options
|
|
12
|
-
globals = {
|
|
13
|
-
:multipart => true,
|
|
14
|
-
:raise_errors => true,
|
|
15
|
-
:convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym}
|
|
16
|
-
}
|
|
17
|
-
http = HTTPI::Response.new(response[:code], response[:headers], response[:body])
|
|
18
|
-
|
|
19
|
-
Savon::Multipart::Response.new(http, globals, {})
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
context "multipart" do
|
|
23
|
-
let(:path) { File.expand_path("../../../fixtures/response/multipart.txt", __FILE__) }
|
|
24
|
-
|
|
25
|
-
it "parses without Exception" do
|
|
26
|
-
expect(response.xml.strip).to eq('<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:wsdl="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><ns1:TransactionID soapenv:actor="" soapenv:mustUnderstand="1" xsi:type="xsd:string" xmlns:ns1="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2">2011012713535811111111111</ns1:TransactionID></soapenv:Header><soapenv:Body><SubmitReq xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2"><MM7Version>5.3.0</MM7Version><SenderIdentification><VASPID>messaging</VASPID><VASID>ADM</VASID><SenderAddress><ShortCode>1111</ShortCode></SenderAddress></SenderIdentification><Recipients><To><Number>11111111111</Number></To></Recipients><ServiceCode>1</ServiceCode><MessageClass>Personal</MessageClass><ExpiryDate>2011-01-28T13:53:58Z</ExpiryDate><DeliveryReport>false</DeliveryReport><ReadReply>false</ReadReply><Priority>Normal</Priority><Subject>Test MMS via Savon</Subject><ChargedParty>Sender</ChargedParty><Content href="cid:attachment_1" allowAdaptations="true"/></SubmitReq></soapenv:Body></soapenv:Envelope>')
|
|
27
|
-
expect(response.parts.length).to eq(2)
|
|
28
|
-
expect(response.parts[1].parts.length).to eq(3)
|
|
29
|
-
expect(response.parts[1].parts[2].body.decoded.strip).to eq("This is a test message from Github")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it "returns the attachments" do
|
|
33
|
-
expect(response.attachments.size).to eq(1)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it "only parses the SOAP body once" do
|
|
37
|
-
Mail::Part.stub(:new).and_return(double(Mail::Part).as_null_object)
|
|
38
|
-
expect(Mail::Part).to receive(:new).exactly(1).times
|
|
39
|
-
5.times { response.attachments }
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context "simple multipart" do
|
|
44
|
-
let(:path) { File.expand_path('../../../fixtures/response/simple_multipart.txt', __FILE__) }
|
|
45
|
-
|
|
46
|
-
it "returns a String from the #xml method" do
|
|
47
|
-
expect(response.xml.class).to eq(String)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it "returns a Hash from the #body method" do
|
|
51
|
-
expect(response.body.class).to eq(Hash)
|
|
52
|
-
expect(response.body).to eq({:submit_req => true})
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
describe "a multipart response with case sensitive headers" do
|
|
57
|
-
let(:header) {{ "Content-Type" => 'MuLtIpArT/rElAtEd; boundary="--==_mimepart_4d416ae62fd32_201a8043814c4724"; charset=UTF-8; type="text/xml"' }}
|
|
58
|
-
let(:path) { File.expand_path('../../../fixtures/response/simple_multipart.txt', __FILE__) }
|
|
59
|
-
|
|
60
|
-
it "does not care about upper or lowercase values for ContentType" do
|
|
61
|
-
expect(response.body).to eq({:submit_req => true})
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
context "not multipart" do
|
|
66
|
-
let(:path) { File.expand_path('../../../fixtures/response/not_multipart.txt', __FILE__) }
|
|
67
|
-
let(:header) { { 'Content-Type' => 'text/html; charset=utf-8'} }
|
|
68
|
-
|
|
69
|
-
it "parses soap messages without attachments too" do
|
|
70
|
-
expect(response.xml.chomp).to eq('<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:wsdl="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><ns1:TransactionID soapenv:actor="" soapenv:mustUnderstand="1" xsi:type="xsd:string" xmlns:ns1="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2">2011012713535811111111111</ns1:TransactionID></soapenv:Header><soapenv:Body><SubmitReq xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2"><MM7Version>5.3.0</MM7Version><SenderIdentification><VASPID>messaging</VASPID><VASID>ADM</VASID><SenderAddress><ShortCode>1111</ShortCode></SenderAddress></SenderIdentification><Recipients><To><Number>11111111111</Number></To></Recipients><ServiceCode>1</ServiceCode><MessageClass>Personal</MessageClass><ExpiryDate>2011-01-28T13:53:58Z</ExpiryDate><DeliveryReport>false</DeliveryReport><ReadReply>false</ReadReply><Priority>Normal</Priority><Subject>Test MMS via Savon</Subject><ChargedParty>Sender</ChargedParty><Content href="cid:attachment_1" allowAdaptations="true"/></SubmitReq></soapenv:Body></soapenv:Envelope>')
|
|
71
|
-
expect(response.parts.size).to eq(0)
|
|
72
|
-
expect(response.attachments.size).to eq(0)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context "soap errors" do
|
|
77
|
-
let(:path) { File.expand_path('../../../fixtures/response/soap_fault.txt', __FILE__) }
|
|
78
|
-
|
|
79
|
-
it "handles them correctly" do
|
|
80
|
-
expect { response }.to raise_error(Savon::SOAPFault, /The service cannot be found/)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|