From b557add4fc28feff4d0e8e6b95a6898b88faab0e Mon Sep 17 00:00:00 2001 From: "Warren R. Bank" Date: Thu, 27 Feb 2020 05:34:43 -0800 Subject: [PATCH] add permissive CORS response header * for the SPA web app: - requests are sent one-way to the server - responses are ignored * commands are issued * nothing meaningful is communicated back - lack of a CORS response header results in: * the browser blocking data in the response * a warning logged to the javascript console - adding this header: * makes no functional difference * prevents the log messages * for other web clients: - there are AirPlay endpoints that return metadata - if any of this data is queried, this CORS header will permit the client to read it --- .../httpcore/RequestListenerThread.java | 55 ++++++++----------- android-studio-project/constants.gradle | 4 +- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java index f736fdf..31270ea 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java @@ -290,7 +290,7 @@ public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpConte httpResponse.setStatusCode(HttpStatus.SC_NO_CONTENT); //204 No Content httpResponse.setHeader("Date", new Date().toString()); - httpResponse.setHeader("Access-Control-Allow-Origin", origin); + httpResponse.setHeader("Access-Control-Allow-Origin", origin); httpResponse.setHeader("Access-Control-Allow-Headers", headers); httpResponse.setHeader("Access-Control-Allow-Methods", methods); httpResponse.setHeader("Allow", methods); @@ -356,14 +356,13 @@ public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpConte } } else if (target.equals(Constant.Target.SERVER_INFO)) { + setCommonHeaders(httpResponse, HttpStatus.SC_OK); + String responseStr = Constant.getServerInfoResponse(localMac); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); httpResponse.setEntity(new StringEntity(responseStr)); } else if (target.equals(Constant.Target.STOP)) { //Stop message - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); Message msg = Message.obtain(); msg.what = Constant.Msg.Msg_Stop; @@ -375,8 +374,7 @@ else if (target.equals(Constant.Target.STOP)) { //Stop message photoCacheMaps.clear(); } else if (target.equals(Constant.Target.PHOTO)) { //Pushed image - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); Message msg = Message.obtain(); msg.what = Constant.Msg.Msg_Photo; @@ -437,8 +435,7 @@ else if (target.equals(Constant.Target.PLAY) && (entityContent != null)) { //Pus if (playUrl.isEmpty()) { Log.d(tag, "airplay video URL missing"); - httpResponse.setStatusCode(HttpStatus.SC_BAD_REQUEST); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST); } else { Log.d(tag, "airplay playUrl = " + playUrl + "; start Pos = " + startPos); @@ -451,8 +448,7 @@ else if (target.equals(Constant.Target.PLAY) && (entityContent != null)) { //Pus msg.obj = map; MainApp.broadcastMessage(msg); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } } else if (target.startsWith(Constant.Target.SCRUB)) { //POST is the seek operation. GET returns the position and duration of the play. @@ -498,8 +494,7 @@ else if (target.startsWith(Constant.Target.SCRUB)) { //POST is the seek operatio } } - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); httpResponse.setEntity(returnBody); } else if (target.startsWith(Constant.Target.RATE)) { //Set playback rate (special case: 0 is pause) @@ -514,8 +509,7 @@ else if (target.startsWith(Constant.Target.RATE)) { //Set playback rate (special MainApp.broadcastMessage(msg); } - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } //IOS 8.4.1 Never send this command (Youku does not send, Tencent video sends) else if (target.equalsIgnoreCase(Constant.Target.PLAYBACK_INFO)) { @@ -551,15 +545,14 @@ else if (target.equalsIgnoreCase(Constant.Target.PLAYBACK_INFO)) { httpContext.setAttribute(Constant.ReverseMsg, Constant.getVideoEventMsg(sessionId, status)); } - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); httpResponse.setHeader("Content-Type", "text/x-apple-plist+xml"); httpResponse.setEntity(new StringEntity(playback_info)); } else if (target.equals("/fp-setup")) { Log.d(tag, "airplay setup content = " + new String(entityContent, "UTF-8")); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } // ======================================================================= // non-standard extended API methods: @@ -591,8 +584,7 @@ else if (target.equals(Constant.Target.QUEUE) && (entityContent != null)) { //Ad if (playUrl.isEmpty()) { Log.d(tag, "airplay video URL missing"); - httpResponse.setStatusCode(HttpStatus.SC_BAD_REQUEST); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST); } else { Log.d(tag, "airplay playUrl = " + playUrl + "; start Pos = " + startPos + "; referer = " + referUrl); @@ -606,8 +598,7 @@ else if (target.equals(Constant.Target.QUEUE) && (entityContent != null)) { //Ad msg.obj = map; MainApp.broadcastMessage(msg); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } } else if (target.equals(Constant.Target.NEXT)) { //skip forward to next video in queue @@ -615,16 +606,14 @@ else if (target.equals(Constant.Target.NEXT)) { //skip forward to next video in msg.what = Constant.Msg.Msg_Video_Next; MainApp.broadcastMessage(msg); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } else if (target.equals(Constant.Target.PREVIOUS)) { //skip backward to previous video in queue Message msg = Message.obtain(); msg.what = Constant.Msg.Msg_Video_Prev; MainApp.broadcastMessage(msg); - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } else if (target.startsWith(Constant.Target.VOLUME)) { //set audio volume (special case: 0 is mute) String value = StringUtils.getQueryStringValue(target, "?value="); @@ -638,16 +627,20 @@ else if (target.startsWith(Constant.Target.VOLUME)) { //set audio volume (specia MainApp.broadcastMessage(msg); } - httpResponse.setStatusCode(HttpStatus.SC_OK); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_OK); } // ======================================================================= else { Log.d(tag, "airplay default not process"); - httpResponse.setStatusCode(HttpStatus.SC_BAD_REQUEST); - httpResponse.setHeader("Date", new Date().toString()); + setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST); } } + + private static void setCommonHeaders(HttpResponse httpResponse, int statusCode) { + httpResponse.setStatusCode(statusCode); + httpResponse.setHeader("Access-Control-Allow-Origin", "*"); + httpResponse.setHeader("Date", new Date().toString()); + } } } diff --git a/android-studio-project/constants.gradle b/android-studio-project/constants.gradle index 47774e8..98847c9 100644 --- a/android-studio-project/constants.gradle +++ b/android-studio-project/constants.gradle @@ -1,6 +1,6 @@ project.ext { - releaseVersionCode = Integer.parseInt("001000316", 10) - releaseVersion = '001.00.03-16API' + releaseVersionCode = Integer.parseInt("001000416", 10) + releaseVersion = '001.00.04-16API' minSdkVersion = 16 targetSdkVersion = 28 compileSdkVersion = 28