* Processes a JSONP request and returns an event stream of the results. * @param req The request object. * @returns An observable of the response events. *
(req: HttpRequest<never>)
| 120 | * |
| 121 | */ |
| 122 | handle(req: HttpRequest<never>): Observable<HttpEvent<any>> { |
| 123 | // Firstly, check both the method and response type. If either doesn't match |
| 124 | // then the request was improperly routed here and cannot be handled. |
| 125 | if (req.method !== 'JSONP') { |
| 126 | throw new RuntimeError( |
| 127 | RuntimeErrorCode.JSONP_WRONG_METHOD, |
| 128 | ngDevMode && JSONP_ERR_WRONG_METHOD, |
| 129 | ); |
| 130 | } else if (req.responseType !== 'json') { |
| 131 | throw new RuntimeError( |
| 132 | RuntimeErrorCode.JSONP_WRONG_RESPONSE_TYPE, |
| 133 | ngDevMode && JSONP_ERR_WRONG_RESPONSE_TYPE, |
| 134 | ); |
| 135 | } |
| 136 | |
| 137 | // Check the request headers. JSONP doesn't support headers and |
| 138 | // cannot set any that were supplied. |
| 139 | if (req.headers.keys().length > 0) { |
| 140 | throw new RuntimeError( |
| 141 | RuntimeErrorCode.JSONP_HEADERS_NOT_SUPPORTED, |
| 142 | ngDevMode && JSONP_ERR_HEADERS_NOT_SUPPORTED, |
| 143 | ); |
| 144 | } |
| 145 | |
| 146 | if (!this.isAllowedJsonpUrl(req.urlWithParams)) { |
| 147 | throw new RuntimeError(RuntimeErrorCode.JSONP_UNSAFE_URL, ngDevMode && JSONP_ERR_UNSAFE_URL); |
| 148 | } |
| 149 | |
| 150 | // Everything else happens inside the Observable boundary. |
| 151 | return new Observable<HttpEvent<any>>((observer: Observer<HttpEvent<any>>) => { |
| 152 | // The first step to make a request is to generate the callback name, and replace the |
| 153 | // callback placeholder in the URL with the name. Care has to be taken here to ensure |
| 154 | // a trailing &, if matched, gets inserted back into the URL in the correct place. |
| 155 | const callback = this.nextCallback(); |
| 156 | const url = req.urlWithParams.replace(/=JSONP_CALLBACK(&|$)/, `=${callback}$1`); |
| 157 | |
| 158 | // Construct the <script> tag and point it at the URL. |
| 159 | const node = this.document.createElement('script'); |
| 160 | node.src = url; |
| 161 | |
| 162 | // Set the nonce for Content Security Policy compatibility. Without this, |
| 163 | // JSONP requests will be blocked by strict-dynamic CSP policies. |
| 164 | if (this.nonce) { |
| 165 | node.setAttribute('nonce', this.nonce); |
| 166 | } |
| 167 | |
| 168 | // A JSONP request requires waiting for multiple callbacks. These variables |
| 169 | // are closed over and track state across those callbacks. |
| 170 | |
| 171 | // The response object, if one has been received, or null otherwise. |
| 172 | let body: any | null = null; |
| 173 | |
| 174 | // Whether the response callback has been called. |
| 175 | let finished: boolean = false; |
| 176 | |
| 177 | // Set the response callback in this.callbackMap (which will be the window |
| 178 | // object in the browser. The script being loaded via the <script> tag will |
| 179 | // eventually call this callback. |
nothing calls this directly
no test coverage detected