You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by "Andrew Greenburg (Jira)" <ji...@apache.org> on 2019/12/02 19:45:00 UTC

[jira] [Created] (NIFI-6920) InvokeHttp convertAttributesFromHeaders() method creates attributes with empty string keys, leading to failure on validation

Andrew Greenburg created NIFI-6920:
--------------------------------------

             Summary: InvokeHttp convertAttributesFromHeaders() method creates attributes with empty string keys, leading to failure on validation
                 Key: NIFI-6920
                 URL: https://issues.apache.org/jira/browse/NIFI-6920
             Project: Apache NiFi
          Issue Type: Bug
          Components: Core Framework
    Affects Versions: 1.9.2
            Reporter: Andrew Greenburg


When the InvokeHttp processor receives a response, it automatically adds all of the HTTP response headers to the response flowfile as attributes.

See line 854 of [https://github.com/apache/nifi/blob/rel/nifi-1.9.2/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java] :
{code:java}
// write the response headers as attributes
// this will overwrite any existing flowfile attributes
responseFlowFile = session.putAllAttributes(responseFlowFile, convertAttributesFromHeaders(url, responseHttp));
{code}
 
In some cases, the Response contains headers where the key is an empty string, but the convertAttributesFromHeaders() method only has a safety check for keys that are null:

{code:Java}
    private Map<String, String> convertAttributesFromHeaders(URL url, Response responseHttp){
        // create a new hashmap to store the values from the connection
        Map<String, String> map = new HashMap<>();
        responseHttp.headers().names().forEach( (key) -> {
                if (key == null) {
                    return;
                }

                List<String> values = responseHttp.headers().values(key);

                // we ignore any headers with no actual values (rare)
                if (values == null || values.isEmpty()) {
                    return;
                }

                // create a comma separated string from the values, this is stored in the map
                String value = csv(values);

                // put the csv into the map
                map.put(key, value);
        });

        if (responseHttp.request().isHttps()) {
            Principal principal = responseHttp.handshake().peerPrincipal();

            if (principal != null) {
                map.put(REMOTE_DN, principal.getName());
            }
        }

        return map;
    }
{code}

This causes the following error in Nifi, which routes the flowfile to failure:

{code}
2019-12-02 19:18:36,416 ERROR [Timer-Driven Process Thread-2] o.a.nifi.processors.standard.InvokeHTTP InvokeHTTP[id=e127afdd-12b8-38cc-a2d3-af051d3965cb] Routing to Failure due to exception: java.lang.IllegalArgumentException: Invalid attribute key: <Empty String>: java.lang.IllegalArgumentException: Invalid attribute key: <Empty String>
java.lang.IllegalArgumentException: Invalid attribute key: <Empty String>
	at org.apache.nifi.flowfile.FlowFile$KeyValidator.validateKey(FlowFile.java:120)
	at org.apache.nifi.controller.repository.StandardFlowFileRecord$Builder.addAttributes(StandardFlowFileRecord.java:238)
	at org.apache.nifi.controller.repository.StandardProcessSession.putAllAttributes(StandardProcessSession.java:1796)
	at org.apache.nifi.processors.standard.InvokeHTTP.onTrigger(InvokeHTTP.java:854)
	at org.apache.nifi.processor.AbstractProcessor.onTrigger(AbstractProcessor.java:27)
	at org.apache.nifi.controller.StandardProcessorNode.onTrigger(StandardProcessorNode.java:1162)
	at org.apache.nifi.controller.tasks.ConnectableTask.invoke(ConnectableTask.java:209)
	at org.apache.nifi.controller.scheduling.TimerDrivenSchedulingAgent$1.run(TimerDrivenSchedulingAgent.java:117)
	at org.apache.nifi.engine.FlowEngine$2.run(FlowEngine.java:110)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
{code}

Here is an HTTP response that I can consistently reproduce this issue with:

{code}
HTTP/1.1 200 OK
Server: openresty/1.15.8.1
Date: Wed, 27 Nov 2019 15:07:20 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 190
Connection: keep-alive
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
Referrer-Policy: no-referrer
set-cookie: access_token=vmpxF4JrHGOeRvoSB; Max-Age=1209600; Expires=Wed, 11 Dec 2019 15:07:20 GMT; Path=/
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: script-src https://10.0.0.196:* 'unsafe-inline' 'unsafe-eval' blob: ;
                                         img-src https://10.0.0.196:* data: ;
                                       frame-src https://10.0.0.196:* 'unsafe-inline' 'unsafe-eval' blob: ;
                                       style-src https://10.0.0.196:* 'unsafe-inline' ;
                                        font-src https://10.0.0.196:* data: ;
                                     default-src https://10.0.0.196:* ;
                                      object-src 'none' 
{code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)