Skip to content

Commit f76c05e

Browse files
authored
Merge pull request #1 from fukamachi/master
Pull in Fukumachi's advances.
2 parents b2593d5 + 4bc8cdd commit f76c05e

File tree

386 files changed

+23227
-19943
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

386 files changed

+23227
-19943
lines changed

api.lisp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@
5656
:method (request-method req)
5757
:host (request-host req region)
5858
:path (quri:uri-path uri)
59-
:params (quri:uri-query-params uri)
59+
:params (mapcar (lambda (kv)
60+
(if (null (cdr kv))
61+
(cons (car kv) "")
62+
kv))
63+
(quri:uri-query-params uri))
6064
:headers headers
6165
:payload (or payload "")))
6266
(multiple-value-list

credentials/ec2role.lisp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
#:retrieve
77
#:provider-expiration)
88
(:import-from #:aws-sdk/ec2metadata
9-
#:ec2metadata)
9+
#:ec2metadata
10+
#:ec2token)
1011
(:import-from #:trivial-timeout
1112
#:timeout-error)
1213
(:import-from #:cl-ppcre)
@@ -18,13 +19,44 @@
1819
(defclass ec2role-provider (provider)
1920
())
2021

22+
(defvar *default-token-ttl* 21600)
23+
(defvar *token* nil)
24+
(defvar *use-imds-v2* t)
25+
26+
(defstruct token
27+
(ttl *default-token-ttl* :type integer)
28+
(value nil :type string)
29+
(created-at (get-universal-time) :type integer))
30+
31+
(defun token-alive-p (token)
32+
(and (token-p token)
33+
(<= (+ (token-created-at token) (token-ttl token))
34+
(get-universal-time))))
35+
36+
(defun fetch-token ()
37+
(when *use-imds-v2*
38+
(if (token-alive-p *token*)
39+
(token-value *token*)
40+
(handler-case
41+
(let ((new-token (ec2token *default-token-ttl*)))
42+
(setf *token* (make-token :value new-token))
43+
new-token)
44+
((or dex:http-request-forbidden
45+
dex:http-request-not-found
46+
dex:http-request-method-not-allowed) ()
47+
(setf *use-imds-v2* nil)
48+
nil)))))
49+
2150
(defmethod retrieve ((provider ec2role-provider))
2251
(handler-case
23-
(let ((role (ppcre:scan-to-strings "^.+?(?=(?:[\\r\\n]|$))"
24-
(ec2metadata "/iam/security-credentials/"))))
52+
(let* ((token (fetch-token))
53+
(role (ppcre:scan-to-strings "^.+?(?=(?:[\\r\\n]|$))"
54+
(ec2metadata "/iam/security-credentials/"
55+
:token token))))
2556
(when role
2657
(let ((res (yason:parse
27-
(ec2metadata (format nil "/iam/security-credentials/~A" role)))))
58+
(ec2metadata (format nil "/iam/security-credentials/~A" role)
59+
:token token))))
2860
(setf (provider-expiration provider)
2961
(local-time:parse-timestring (gethash "Expiration" res)))
3062
(make-credentials

ec2metadata.lisp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@
55
#:with-timeout
66
#:timeout-error)
77
(:export #:ec2metadata
8+
#:ec2token
89
#:ec2-region))
910
(in-package #:aws-sdk/ec2metadata)
1011

11-
(defun ec2metadata (path)
12+
(defun ec2metadata (path &key token)
1213
(with-timeout (5)
1314
(dex:get (format nil "http://169.254.169.254/latest/meta-data~A"
1415
(or path "/"))
16+
:headers `(,@(and token `(("x-aws-ec2-metadata-token" . ,token))))
17+
:keep-alive nil)))
18+
19+
(defun ec2token (ttl)
20+
(check-type ttl (integer 1))
21+
(with-timeout (5)
22+
(dex:put "http://169.254.169.254/latest/api/token"
23+
:headers `(("x-aws-ec2-metadata-token-ttl-seconds" . ,ttl))
1524
:keep-alive nil)))
1625

1726
(defun ec2-region ()

generator/operation.lisp

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,39 @@
7777
:status status
7878
:body body-str)))
7979

80-
(defun parse-response (response body-type wrapper-name error-map)
80+
(defun parse-response (response body-type wrapper-name error-map &optional default-content-type)
8181
(destructuring-bind (body status headers &rest ignore-args)
8282
response
83+
;; TODO: Parse also from headers
8384
(declare (ignore ignore-args))
84-
(let ((content-type (gethash "content-type" headers)))
85+
(let ((content-type (or (gethash "content-type" headers)
86+
default-content-type)))
8587
(if (<= 400 status 599)
8688
(parse-response-error body status content-type error-map)
87-
(if (equal body-type "blob")
88-
body
89-
(let ((body-str (ensure-string (or body ""))))
90-
(cond
91-
((or (string-prefix-p "text/xml" content-type)
92-
(string-prefix-p "application/xml" content-type))
93-
(let* ((output (xmls-to-alist (xmls:parse-to-list body-str)))
94-
(output ;; Unwrap the root element
95-
(cdr (first output))))
96-
(if wrapper-name
97-
(values (aget output wrapper-name)
98-
(aget output "ResponseMetadata"))
99-
output)))
100-
((member content-type '("application/json" "application/x-amz-json-1.1" "application/x-amz-json-1.0")
101-
:test #'string=)
102-
(yason:parse body-str :object-as :alist))
103-
(t
104-
body-str))))))))
89+
(values
90+
(if (or (= status 204)
91+
(equal body-type "blob"))
92+
body
93+
(let ((body-str (ensure-string (or body ""))))
94+
(cond
95+
((or (string-prefix-p "text/xml" content-type)
96+
(string-prefix-p "application/xml" content-type))
97+
(if (string= body-str "")
98+
body-str
99+
(let* ((output (xmls-to-alist (xmls:parse-to-list body-str)))
100+
(output ;; Unwrap the root element
101+
(cdr (first output))))
102+
(if wrapper-name
103+
(values (aget output wrapper-name)
104+
(aget output "ResponseMetadata"))
105+
output))))
106+
((member content-type '("application/json" "application/x-amz-json-1.1" "application/x-amz-json-1.0")
107+
:test #'string=)
108+
(yason:parse body-str :object-as :alist))
109+
(t
110+
body-str))))
111+
status
112+
headers)))))
105113

106114
(defun aws-sign4-uri-encode (data &optional path?)
107115
(replace-using
@@ -142,7 +150,7 @@
142150
,@slots))
143151
path-pattern))))
144152

145-
(defun compile-operation (service name options params body-type error-map)
153+
(defun compile-operation (service name options params body-type error-map protocol)
146154
(let* ((output (gethash "output" options))
147155
(method (gethash "method" (gethash "http" options)))
148156
(request-uri (gethash "requestUri" (gethash "http" options))))
@@ -162,7 +170,10 @@
162170
,body-type
163171
,(and output
164172
(gethash "resultWrapper" output))
165-
,error-map)))
173+
,error-map
174+
,(case protocol
175+
((:json :rest-json) "application/json")
176+
(:rest-xml "application/xml")))))
166177
(export ',(lispify name))))
167178
`(progn
168179
(defun ,(lispify name) ()

generator/service.lisp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
(request-name (intern (format nil "~:@(~A-REQUEST~)" service))))
3636
(format stream "~&;; DO NOT EDIT: File is generated by AWS-SDK/GENERATOR.~2%")
3737
(format stream "~&~S~%"
38-
`(defpackage ,package-name
38+
`(uiop:define-package ,package-name
3939
(:use)
4040
(:nicknames ,(make-symbol (format nil "~:@(~A/~A~)" :aws service)))
4141
(:import-from #:aws-sdk/generator/shape)
@@ -110,7 +110,8 @@
110110
(find-output-type
111111
(gethash+ `("shapes" ,(gethash "shape" shape)) hash))))))
112112
(find-output-type payload-shape))))
113-
(intern (string :*error-map*)))))
113+
(intern (string :*error-map*))
114+
protocol)))
114115
(force-output stream)))))
115116

116117
(defun dump-service-base-file-to-stream (service service-dir &optional (stream *standard-output*))

generator/shape.lisp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
(:method (input) input))
4040
(defgeneric input-headers (input))
4141
(defgeneric input-payload (input))
42+
(defgeneric input-payload-properties (input)
43+
(:method (input) (declare (ignore input)) nil))
4244

4345
(defun add-query-with-input (uri input)
4446
(quri:render-uri
@@ -57,15 +59,16 @@
5759
(declare (debug 3))
5860
(make-instance request-class
5961
:method method
60-
:path (add-query-with-input
61-
(etypecase path-conversion
62-
(string path-conversion)
63-
(function (funcall path-conversion input))
64-
(null "/"))
65-
input)
62+
:path (quri:render-uri (add-query-with-input
63+
(etypecase path-conversion
64+
(string path-conversion)
65+
(function (funcall path-conversion input))
66+
(null "/"))
67+
input))
6668
:params (input-params input)
6769
:headers (input-headers input)
6870
:payload (input-payload input)
71+
:payload-properties (input-payload-properties input)
6972
:operation action))
7073

7174
(defun filter-member (key value members)
@@ -130,7 +133,17 @@
130133
(defmethod input-payload ((input ,shape-name))
131134
,(if payload
132135
`(slot-value input ',(lispify payload))
133-
'nil)))))
136+
'nil))
137+
,@(when (and payload
138+
(gethash payload members))
139+
(let ((props (gethash payload members)))
140+
`((defmethod input-payload-properties ((input ,shape-name))
141+
(declare (ignore input))
142+
(list ,@(and (gethash "locationName" props)
143+
`(:location-name ,(gethash "locationName" props)))
144+
,@(and (gethash "xmlNamespace" props)
145+
(gethash "uri" (gethash "xmlNamespace" props))
146+
`(:xml-namespace ,(gethash "uri" (gethash "xmlNamespace" props))))))))))))
134147

135148
(defun compile-exception-shape (name &key members exception)
136149
(let ((condition-name (lispify* name)))

request.lisp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
(payload :initarg :payload
6363
:initform nil
6464
:accessor request-payload)
65+
(payload-properties :initarg :payload-properties
66+
:initform nil
67+
:accessor request-payload-properties)
6568
(session :initarg :session
6669
:initform *session*
6770
:reader request-session)))

rest-xml-request.lisp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,44 @@
33
(:import-from #:aws-sdk/request
44
#:request
55
#:request-headers
6-
#:request-path)
6+
#:request-path
7+
#:request-payload)
78
(:import-from #:aws-sdk/session
89
#:*session*)
10+
(:import-from #:xml-emitter)
911
(:export #:rest-xml-request))
1012
(in-package #:aws-sdk/rest-xml-request)
1113

1214
(defclass rest-xml-request (request)
1315
())
1416

17+
(defun object-to-xml (object location-name &optional xml-namespace)
18+
(assert location-name)
19+
(typecase object
20+
(null)
21+
;; XXX: Should see if it's flattened or not.
22+
(cons (map nil (lambda (obj) (object-to-xml obj location-name))
23+
object))
24+
(standard-object
25+
(xml-emitter:with-simple-tag (location-name nil xml-namespace)
26+
(loop for slot in (c2mop:class-direct-slots (class-of object))
27+
for value = (slot-value object (c2mop:slot-definition-name slot))
28+
for tag-name = (or (aws-sdk/generator/shape::member-slot-location-name slot)
29+
(aws-sdk/generator/shape::member-slot-shape slot))
30+
when value
31+
do (if tag-name
32+
(object-to-xml value tag-name)
33+
(xml-emitter:xml-out value)))))
34+
(otherwise
35+
(xml-emitter:simple-tag location-name object nil xml-namespace))))
1536

16-
(defmethod initialize-instance :after ((req rest-xml-request) &rest args &key params path &allow-other-keys)
37+
(defmethod initialize-instance :after ((req rest-xml-request) &rest args &key path payload payload-properties &allow-other-keys)
1738
(declare (ignore args))
18-
(let ((uri (quri:uri path)))
19-
(setf (request-path req)
20-
(quri:render-uri
21-
(quri:make-uri :path (quri:uri-path uri)
22-
:query (quri:url-encode-params (append (quri:uri-query-params uri)
23-
params)))))))
39+
(when (typep payload 'standard-object)
40+
(destructuring-bind (&key location-name xml-namespace)
41+
payload-properties
42+
(setf (request-payload req)
43+
(with-output-to-string (s)
44+
(xml-emitter:with-xml-output (s :encoding "UTF-8")
45+
(object-to-xml payload location-name xml-namespace))))))
46+
(setf (request-path req) path))

0 commit comments

Comments
 (0)