IHTTPStreamerSession.rejectClient() not working as expected

Hi.

I have a custom module in which i reject the httpSession using the rejectClient() method if i don’t find a specific header with a specific value.

It’s mostly working but i am getting mixed results, on average only 4 in 10 requests get blocked and receive 403, the rest get 200, i am using curl and ffprobe to test, and querying http://server/applicationname/stream/playlist.m3u8 in my tests. Also, when i test with the same url and use vlc, it always plays the stream.

Any new ideas of what i might be missing are very appreciated.

Here is the code:

package com.company.wowza.wms.module;

import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.httpstreamer.model.*;
import com.wowza.wms.module.*;

public class ModuleAccessControlHTTPStreaming extends ModuleBase {

    static String allowedHeaderName;
    static String allowedHeaderValue;
    
    public void onAppStart(IApplicationInstance appInstance) {
        String fullname = appInstance.getApplication().getName() + "/" + appInstance.getName();
        
        getLogger().info("ModuleAccessControlHTTPStreaming, onAppStart app: " + fullname);
        
        allowedHeaderName = appInstance.getProperties()
                .getPropertyStr("ModuleAccessControlHTTPStreamingHeaderName", "CF_EDGE_SERVER");
        allowedHeaderValue = appInstance.getProperties()
                .getPropertyStr("ModuleAccessControlHTTPStreamingHeaderValue", "TRUE");
        
        getLogger().debug("ModuleAccessControlHTTPStreaming, Properties H: " + allowedHeaderName + ", V: " + allowedHeaderValue);
    }
    
    public void onHTTPSessionCreate(IHTTPStreamerSession httpSession) {
        boolean rejectClient = true;
        
        String userAgent       = httpSession.getUserAgent();
        String ipAddressClient = httpSession.getIpAddress();
        
        java.util.Map<String,String> HTTPHeaders = httpSession.getHTTPHeaderMap();
        
        for(java.util.Map.Entry<String, String> header : HTTPHeaders.entrySet()) {
            String headerName = header.getKey();
            String headerValue  = header.getValue();
            
            getLogger().debug("ModuleAccessControlHTTPStreaming, H: " + headerName + ", V: " + headerValue);
            
            if (
                headerName.equalsIgnoreCase(allowedHeaderName) &&
                headerValue.equalsIgnoreCase(allowedHeaderValue)
            ) {
                rejectClient = false;
                break;
            }
        }
        
        if (rejectClient) {
            getLogger().warn("ModuleAccessControlHTTPStreaming, Client Rejected, UA: " + userAgent + ", IP: " + ipAddressClient);
            httpSession.rejectSession();
        } else
            getLogger().info("ModuleAccessControlHTTPStreaming, Client Accepted, UA: " + userAgent + ", IP: " + ipAddressClient);    
    }
}

P.S. If my code has no design and/or logic flaws/bugs, it could be that this might be a bug in the java api.

Have you (1) checked your logs and (2) stepped through the code in debug mode? You’re assuming that httpSession.getUserAgent, httpSession.getIpAddress and httpSession.getHTTPHeaderMap always return values - what if they return NULL? I recall e.g. older VLC versions didn’t always send all values - as VLC basically emulates a HTTP session …

So first of all.

Hi Karel and thanks for the reply.

To address your concerns regarding the code:

The default is to reject a client, then the processing begins, if the processing does not work as intended or if some properties are not set, the default should still be to reject the session and an optional exception thrown if that would be the case. So in short, if things go wrong clients should all be reject, not accepted as my case is.

Second of all.

A bit off topic.

This community platforms is really poor, i wrote my response and when i posted it i got redirected to https://www.wowza.com/community/static/csrfAttackDetected.html because my session expired and i had no idea from the UI until i typed my message and pressed the “Post Answer” button. So after this nightmare 2019 web page with 2003 design and functionality, i had to write everything again. Also the reCAPTCHA is too aggressive for a page and a feature (add or edit post) that is accessible only when logged in. Poor administrator design also.

Now back to my issue.

After two days of debugging i got to the bottom of the problem.

When a client initiates a request and it does NOT have the correct header name and value the session is rejected and onHTTPSessionDestroy is called also at the end.

When a client initiates a request and it has the correct header name and value the session never gets destroyed, i never see onHTTPSessionDestroy being called.

All other requests in a given period of time (somewhere under 30 seconds) will be treated as part of that session and accepted by default, the module is not being ran for any of them, onHTTPSessionCreate or onHTTPSessionDestroy never get called. This works for every session (in my case for any subsequent curl requests after the successful one) even though i removed the correct header+value, tried from another IP, tried with another program like ffprobe, it all gets accepted if it comes after a short period after the correct request with the correct header+value or after any of the others that came after the correct one.

So i don’t know how this sessions sticks to the client and by what arbitrary value, but i need to end the session of the correct request immediately after the client disconnects, without this ~30 second gap in which all request to that application seem to be considered as the same session.