From 47b8ea5f7c2ef1fb3bfb3621bd398a4b0ff86d4f Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Thu, 20 Mar 2014 17:55:20 -0700 Subject: [PATCH] Added Drag & Drop browser file upload demo based on filedropjs.org --- GCDWebServer.xcodeproj/project.pbxproj | 24 +++++++ Mac/filedrop-min.js | 11 ++++ Mac/index.html | 91 ++++++++++++++++++++++++++ Mac/main.m | 40 ++++++++++- 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100755 Mac/filedrop-min.js create mode 100755 Mac/index.html diff --git a/GCDWebServer.xcodeproj/project.pbxproj b/GCDWebServer.xcodeproj/project.pbxproj index 2bcd48a..6f5f296 100644 --- a/GCDWebServer.xcodeproj/project.pbxproj +++ b/GCDWebServer.xcodeproj/project.pbxproj @@ -79,6 +79,8 @@ E22112981690B7AA0048D2B2 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; E221129A1690B7B10048D2B2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; E221129C1690B7BA0048D2B2 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + E263213318DB688E00D9DC0C /* index.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; + E263213418DB7F7900D9DC0C /* filedrop-min.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "filedrop-min.js"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -145,6 +147,8 @@ E221128D1690B6470048D2B2 /* Mac */ = { isa = PBXGroup; children = ( + E263213418DB7F7900D9DC0C /* filedrop-min.js */, + E263213318DB688E00D9DC0C /* index.html */, E221128E1690B6470048D2B2 /* main.m */, ); path = Mac; @@ -293,6 +297,16 @@ buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; MACOSX_DEPLOYMENT_TARGET = 10.7; + OTHER_LDFLAGS = ( + "-sectcreate", + __TEXT, + _index_html_, + "\"Mac/index.html\"", + "-sectcreate", + __TEXT, + _filedrop_js_, + "\"Mac/filedrop-min.js\"", + ); PRODUCT_NAME = GCDWebServer; SDKROOT = macosx; }; @@ -303,6 +317,16 @@ buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; MACOSX_DEPLOYMENT_TARGET = 10.7; + OTHER_LDFLAGS = ( + "-sectcreate", + __TEXT, + _index_html_, + "\"Mac/index.html\"", + "-sectcreate", + __TEXT, + _filedrop_js_, + "\"Mac/filedrop-min.js\"", + ); PRODUCT_NAME = GCDWebServer; SDKROOT = macosx; }; diff --git a/Mac/filedrop-min.js b/Mac/filedrop-min.js new file mode 100755 index 0000000..5bec8d8 --- /dev/null +++ b/Mac/filedrop-min.js @@ -0,0 +1,11 @@ +/*! + FileDrop Revamped - HTML5 & legacy file upload + in public domain | http://filedropjs.org + by Proger_XP | http://proger.me + + Supports IE 6+, FF 3.6+, Chrome 7+, Safari 5+, Opera 11+. + Fork & report problems at https://github.com/ProgerXP/FileDrop +*/ +;window.fd=window.fd||{},function(t,n){t.randomID=function(e){return(e||"fd")+"_"+(Math.random()*1e4).toFixed()},t.uniqueID=function(e){do var n=t.randomID(e);while(t.byID(n));return n},t.byID=function(e){return t.isTag(e)?e:document.getElementById(e)},t.isTag=function(e,t){return typeof e=="object"&&e&&e.nodeType==1&&(!t||e.tagName.toUpperCase()==t.toUpperCase())},t.newXHR=function(){try{return new XMLHttpRequest}catch(e){var t=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];for(var n=0;n=0;u--)t.funcNS(this.events[s[0]][u])==s[1]&&this.events[s[0]].splice(u,1)}return this}}throw"Bad parameters for FileDrop event()."},t.previewToObject=function(e,n){if(t.addEventsToObject(this,!0,arguments))return this;throw"Bad parameters for FileDrop preview()."},t.addEventsToObject=function(e,n,r){var i=r[0],s=r[1];switch(r.length){case 1:if(i&&typeof i=="object"&&!t.isArray(i)){for(var o in i)arguments.callee(e,n,[o,i[o]]);return!0};case 2:if(typeof s=="function"||t.isArray(s)){i=t.toArray(i),s=t.toArray(s);var u=n?"unshift":"push";for(var a=0;a'+'
'+''+''+"
",i.firstChild.setAttribute("id",n),i.firstChild.style.display="none",i.lastChild.setAttribute("target",n);var s=e.firstChild;while(s&&(!t.isTag(s)||t.isTag(s,"legend")))s=s.nextSibling;return s?e.insertBefore(i,s):e.appendChild(i),i.lastChild.lastChild},r.abortIFrame=function(){if(r.opt.input.form){var e=t.byID(r.opt.input.form.getAttribute("target"));e&&e.setAttribute("src","javascript:false")}},r.sendViaIFrame=function(e){e=e||r.opt.iframe.url;var n=(r.opt.input||{}).form;if(e&&n){do var i=t.randomID();while(i in window);window[i]=function(n){typeof n!="object"&&(n={response:n,responseXML:"",responseText:(n||"").toString(),readyState:4,status:200,statusText:"OK",getAllResponseHeaders:function(){return""},getResponseHeader:function(){return""},setRequestHeader:function(){return this},statusCode:function(){return this},abort:function(){return this}}),t.extend(n,{iframe:!0,url:e}),t.callAllOfObject(r,"iframeDone",n)};var s=n.firstChild;while(s&&(!t.isTag(s,"input")||s.name!=r.opt.iframe.callbackParam))s=s.nextSibling;return s?s.value=i:e=e.replace(/[?&]+$/,"")+(e.indexOf("?")==-1?"?":"&")+r.opt.iframe.callbackParam+"="+i,n.setAttribute("action",e),t.callAllOfObject(r,"iframeSetup",n),n.submit(),setTimeout(r.resetForm,300),!0}},r.resetForm=function(){var e=r.opt.input&&r.opt.input.file;if(e){e.value="";if(r.opt.recreateInput){var n=r.opt.input.file=e.cloneNode(!0);e.parentNode.replaceChild(n,e),t.callAllOfObject(r,"inputSetup",[r.opt.input,e])}}},r.multiple=function(e){return r.opt.input&&typeof e!="undefined"&&(e?r.opt.input.file.setAttribute("multiple","multiple"):r.opt.input.file.removeAttribute("multiple")),r.opt.input&&!!r.opt.input.file.getAttribute("multiple")},r.event=function(e,n){return t.appendEventsToObject.apply(r,arguments)},r.preview=function(e,n){return t.previewToObject.apply(r,arguments)},r.onInputSetup=function(n,i){i?(n.file.clearAttributes&&n.file.clearAttributes(),n.file.mergeAttributes&&n.file.mergeAttributes(i)):r.multiple(r.opt.multiple),t.setClass(n.file,r.opt.inputClass),r.delegate(n.file,"change","upload");var s=n.file.parentNode;s&&s.style.display.match(/^(static)?$/)&&(s.style.position="relative");if(t.isTag(e,"fieldset")){var o=document.createElement("div");o.style.position="relative",o.style.overflow="hidden",e.parentNode.insertBefore(o,e),o.appendChild(e)}},r.onDragOver=function(e){t.stopEvent(e),e.dataTransfer&&(e.dataTransfer.dropEffect=r.opt.dropEffect)},r.onUpload=function(){for(var e=0;e0&&t.callAllOfObject(r,"send",[n]):!r.handle.sendViaIFrame()&&t.hasConsole&&console.warn("FileDrop fallback upload triggered but iframe options were not configured - doing nothing.")},r.eventFiles=function(e,n){var i=new t.FileList(e);if(e.dataTransfer&&(e.dataTransfer.length||e.dataTransfer.files))var s=e.dataTransfer;else var s=e.target&&e.target.files||e.srcElement&&e.srcElement.files;if(s){var o=s.items||[];s.files&&(s=s.files);var u={};for(var a=0;a0||f.nativeEntry)&&i.push(f))}}else n&&(i=!1);return i},t.extend(r,r.handle),r.event({upload:r.onUpload,send:r.resetForm,dragEnter:i(!0),dragLeave:i(!1),uploadElsewhere:i(!1)}),r.preview({upload:i(!1)})},t.FileList=function(e){var n=this;n.dropEffect=e&&e.dropEffect||"",n.length=0,e=null,n.push=function(e){return n[n.length++]=e,n},n.pop=function(){if(n.length>0){var e=n.last();return delete n[--n.length],e}},n.first=function(){return n[0]},n.last=function(){return n[n.length-1]},n.remove=function(e){for(;et[1]?1:e[1]0||n.end!=null&&n.end)n.blob.slice?(n.end==null&&(n.end=n.blob.size||n.blob.fileSize),n.blob=n.blob.slice(n.start,n.end,n.mime)):t.hasConsole&&console.warn("File Blob/slice() are unsupported - operating on entire File.");var s=new FileReader;s.onerror=function(e){i("read",e)},s.onload=function(e){if(e.target&&e.target.result){if(n.func=="readAsBinaryString")try{e.target.result=t.toBinary(e.target.result)}catch(e){return i("normalize",e)}n.onDone(e.target.result)}else s.onerror(e)};var o=n.func;if(t.isArray(o)){var u=o[0];return o[0]=n.blob,s[u].apply(s,o)}if(!o||o=="bin")o="readAsBinaryString";else if(o=="url"||o=="uri"||o=="src")o="readAsDataURL";else if(o=="array")o="readAsArrayBuffer";else if(o=="text")o="readAsText";else if(o.substr(0,4)!="read")return s.readAsText(n.blob,o);return o=="readAsBinaryString"&&!s[o]&&(o="readAsArrayBuffer"),s[o](n.blob)},r.listEntries=function(e,n){if(r.nativeEntry&&r.nativeEntry.isDirectory){n=n||new Function;var i=r.nativeEntry.createReader(),s=new t.FileList,o=0;function u(t){o-=t,o==0&&e&&(e(s),e=null)}return i.readEntries(function(e){for(var r=0;r + + + + Basic FileDrop example + + + + + + + + + +

+ FileDrop basic sample +

+ + +
+ Drop a file inside… +

Or click here to Browse..

+ + +

+ + +

+
+ + + + + \ No newline at end of file diff --git a/Mac/main.m b/Mac/main.m index 02f3c49..f0de3cb 100644 --- a/Mac/main.m +++ b/Mac/main.m @@ -25,11 +25,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#import + #import "GCDWebServer.h" +static NSData* _DataFromTEXTSection(const char* name) { + unsigned long size = 0; + char* ptr = getsectdata("__TEXT", name, &size); + if (!ptr || !size) { + abort(); + } + return [NSData dataWithBytesNoCopy:ptr length:size freeWhenDone:NO]; +} + int main(int argc, const char* argv[]) { BOOL success = NO; - int mode = (argc == 2 ? MIN(MAX(atoi(argv[1]), 0), 2) : 0); + int mode = (argc == 2 ? MIN(MAX(atoi(argv[1]), 0), 3) : 0); @autoreleasepool { GCDWebServer* webServer = [[GCDWebServer alloc] init]; switch (mode) { @@ -83,6 +94,33 @@ int main(int argc, const char* argv[]) { break; } + // Implements drag & drop file upload using http://filedropjs.org (requires Chrome 13+, Firefox 3.6+, IE 10+ or Safari 6+) + case 3: { + [webServer addGETHandlerForPath:@"/" + staticData:_DataFromTEXTSection("_index_html_") + contentType:@"text/html; charset=utf-8" + cacheAge:0]; + [webServer addGETHandlerForPath:@"/filedrop-min.js" + staticData:_DataFromTEXTSection("_filedrop_js_") + contentType:@"application/javascript; charset=utf-8" + cacheAge:0]; + [webServer addHandlerForMethod:@"POST" path:@"/ajax-upload" requestClass:[GCDWebServerFileRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { + + NSString* fileName = GCDWebServerUnescapeURLString([request.headers objectForKey:@"X-File-Name"]); + NSString* inPath = [(GCDWebServerFileRequest*)request filePath]; + NSString* outPath = [@"/tmp" stringByAppendingPathComponent:fileName]; + [[NSFileManager defaultManager] removeItemAtPath:outPath error:NULL]; + if ([[NSFileManager defaultManager] moveItemAtPath:inPath toPath:outPath error:NULL]) { + NSString* message = [NSString stringWithFormat:@"File uploaded to \"%@\"", outPath]; + return [GCDWebServerDataResponse responseWithText:message]; + } else { + return [GCDWebServerResponse responseWithStatusCode:500]; + } + + }]; + break; + } + } success = [webServer runWithPort:8080]; #if !__has_feature(objc_arc)