| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Grails
Revision: 7280
Author: graeme
Date: 21 Aug 2008 06:28:04
Changes:fix for GRAILS-3088
Files:| ... | ...@@ -37,30 +37,51 @@ | |
| 37 | 37 | def mimes = new DefaultAcceptHeaderParser().parse("text/xml; charset=UTF-8") |
| 38 | 38 | |
| 39 | 39 | assertEquals 1, mimes.size() |
| 40 | assertEquals "text/xml", mimes[0].name | |
| 40 | assertEquals "application/xml", mimes[0].name | |
| 41 | 41 | assertEquals "xml", mimes[0].extension |
| 42 | 42 | assertEquals( [charset:'UTF-8'], mimes[0].parameters ) |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | |
| 46 | void testAcceptHeaderOrdering() { | |
| 46 | void testFirefox2AcceptHeaderOrdering() { | |
| 47 | ||
| 48 | ||
| 47 | 49 | def mimes = new DefaultAcceptHeaderParser().parse("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5") |
| 48 | 50 | |
| 49 | assertEquals 6, mimes.size() | |
| 51 | assertEquals 5, mimes.size() | |
| 52 | ||
| 53 | assertEquals( ['application/xhtml+xml','application/xml', 'text/html', 'text/plain', '*/*'], mimes.name ) | |
| 54 | assertEquals( ['html', 'xml', 'html', 'text', 'all'], mimes.extension ) | |
| 55 | ||
| 56 | } | |
| 57 | ||
| 58 | void testFirefox3AcceptHeaderOrdering() { | |
| 59 | ||
| 60 | def mimes = new DefaultAcceptHeaderParser().parse("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") | |
| 61 | ||
| 62 | assertEquals 4, mimes.size() | |
| 63 | ||
| 64 | assertEquals( ['html','html','xml', 'all'], mimes.extension ) | |
| 65 | ||
| 66 | } | |
| 67 | ||
| 68 | void testAcceptHeaderWithQNumberOrdering() { | |
| 69 | def mimes = new DefaultAcceptHeaderParser().parse("text/html,application/xhtml+xml,application/xml;q=1.1,*/*;q=0.8") | |
| 70 | ||
| 71 | assertEquals 4, mimes.size() | |
| 72 | ||
| 73 | assertEquals( ['xml','html','html', 'all'], mimes.extension ) | |
| 50 | 74 | |
| 51 | assertEquals( ['text/html', 'text/plain', '*/*','text/xml', 'application/xml', 'application/xhtml+xml'], mimes.name ) | |
| 52 | assertEquals( ['html', 'text', 'all', 'xml','xml', 'html'], mimes.extension ) | |
| 53 | ||
| 54 | 75 | } |
| 55 | 76 | |
| 56 | 77 | void testPrototypeHeaderOrdering() { |
| 57 | 78 | def mimes = new DefaultAcceptHeaderParser().parse("text/javascript, text/html, application/xml, text/xml, */*") |
| 79 | ||
| 80 | assertEquals 4, mimes.size() | |
| 58 | 81 | |
| 59 | assertEquals 5, mimes.size() | |
| 82 | assertEquals( ["js",'html', 'xml', 'all'], mimes.extension ) | |
| 83 | assertEquals( ["text/javascript",'text/html', 'application/xml', '*/*'], mimes.name ) | |
| 60 | 84 | |
| 61 | assertEquals( ["text/javascript",'text/html', 'application/xml', 'text/xml', '*/*'], mimes.name ) | |
| 62 | assertEquals( ["js",'html', 'xml', 'xml', 'all'], mimes.extension ) | |
| 63 | ||
| 64 | 85 | } |
| 65 | 86 | |
| 66 | 87 | void testOldBrowserHeader() { |
| ... | ...@@ -43,6 +43,13 @@ | |
| 43 | 43 | } |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | def testWithFormatAndEqualQualityGrading = { | |
| 47 | withFormat { | |
| 48 | html { render "<html></html>" } | |
| 49 | xml { render(contentType:"text/xml",text: "<xml></xml>") } | |
| 50 | } | |
| 51 | } | |
| 52 | ||
| 46 | 53 | def testWithFormatAndModel = { |
| 47 | 54 | withFormat { |
| 48 | 55 | js { render "alert('hello')" } |
| ... | ...@@ -163,6 +170,35 @@ | |
| 163 | 170 | assertEquals "html", response.contentAsString |
| 164 | 171 | } |
| 165 | 172 | |
| 173 | void testFirefox2AcceptHeader() { | |
| 174 | request.addHeader "Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" | |
| 175 | def c = ga.getControllerClass("ContentController").newInstance() | |
| 176 | webRequest.controllerName = 'content' | |
| 177 | c.testFormat.call() | |
| 178 | ||
| 179 | ||
| 180 | assertEquals "html", response.contentAsString | |
| 181 | } | |
| 182 | ||
| 183 | void testFirefox3AcceptHeader() { | |
| 184 | request.addHeader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" | |
| 185 | def c = ga.getControllerClass("ContentController").newInstance() | |
| 186 | webRequest.controllerName = 'content' | |
| 187 | c.testFormat.call() | |
| 188 | ||
| 189 | ||
| 190 | assertEquals "html", response.contentAsString | |
| 191 | } | |
| 192 | ||
| 193 | void testFirefox2AcceptHeaderWithFormatOrdering() { | |
| 194 | request.addHeader "Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" | |
| 195 | def c = ga.getControllerClass("ContentController").newInstance() | |
| 196 | webRequest.controllerName = 'content' | |
| 197 | c.testWithFormatAndEqualQualityGrading.call() | |
| 198 | ||
| 199 | assertEquals "<html></html>", response.contentAsString | |
| 200 | assertEquals "html", request.format | |
| 201 | } | |
| 166 | 202 | |
| 167 | 203 | |
| 168 | 204 | void testPrototypeFormat() { |
| ... | ...@@ -26,9 +26,12 @@ | |
| 26 | 26 | */ |
| 27 | 27 | public class MimeType { |
| 28 | 28 | |
| 29 | static final XML = 'application/xml' | |
| 30 | ||
| 31 | ||
| 29 | 32 | private static MIMES |
| 30 | 33 | |
| 31 | MimeType(String n, Map params = null) { | |
| 34 | MimeType(String n, Map params = [q:"1.0"]) { | |
| 32 | 35 | this.name = n |
| 33 | 36 | this.parameters = params |
| 34 | 37 | } |
| ... | ...@@ -38,6 +41,10 @@ | |
| 38 | 41 | String extension |
| 39 | 42 | Map parameters |
| 40 | 43 | |
| 44 | boolean equals(Object o) { o instanceof MimeType && name.equals(o.name) } | |
| 45 | public int hashCode() { name.hashCode() } | |
| 46 | ||
| 47 | ||
| 41 | 48 | String toString() { |
| 42 | 49 | return "MimeType { name=$name,extension=$extension,parameters=$parameters }".toString() |
| 43 | 50 | } |
| ... | ...@@ -20,6 +20,10 @@ | |
| 20 | 20 | import org.apache.commons.logging.* |
| 21 | 21 | |
| 22 | 22 | /** |
| 23 | * Parsed the HTTP accept header into a a list of MimeType instances in the order of priority. Priority is dictated | |
| 24 | * by the order of the mime entries and the associated q parameter. The higher the q parameter the higher the prioirity. | |
| 25 | ||
| 26 | * | |
| 23 | 27 | * @author Graeme Rocher |
| 24 | 28 | * @since 1.0 |
| 25 | 29 | * |
| ... | ...@@ -51,8 +55,7 @@ | |
| 51 | 55 | def i = it.indexOf('=') |
| 52 | 56 | params[it[0..i-1].trim()] = it[i+1..-1].trim() |
| 53 | 57 | } |
| 54 | def mimeList = params.q ? qualifiedMimes : mimes | |
| 55 | createMimeTypeAndAddToList(t[0].trim(),mimeConfig, mimeList, params) | |
| 58 | createMimeTypeAndAddToList(t[0].trim(),mimeConfig, mimes, params) | |
| 56 | 59 | } |
| 57 | 60 | else { |
| 58 | 61 | createMimeTypeAndAddToList(t.trim(),mimeConfig, mimes) |
| ... | ...@@ -64,7 +67,37 @@ | |
| 64 | 67 | return MimeType.createDefaults() |
| 65 | 68 | } |
| 66 | 69 | } |
| 67 | return (qualifiedMimes.sort { it.parameters.q.toBigDecimal() }.reverse() + mimes) as MimeType[] | |
| 70 | ||
| 71 | ||
| 72 | // remove duplicate text/xml and application/xml entries | |
| 73 | MimeType textXml = mimes.find { it.name == 'text/xml' } | |
| 74 | MimeType appXml = mimes.find { it.name == MimeType.XML } | |
| 75 | if(textXml && appXml) { | |
| 76 | // take the largest q value | |
| 77 | appXml.parameters.q = [textXml.parameters.q.toBigDecimal(), appXml.parameters.q.toBigDecimal()].max() | |
| 78 | ||
| 79 | mimes.remove(textXml) | |
| 80 | } | |
| 81 | else if(textXml) { | |
| 82 | textXml.name = MimeType.XML | |
| 83 | } | |
| 84 | ||
| 85 | if(appXml) { | |
| 86 | // prioritise more specific XML types like xhtml+xml if they are of equal quality | |
| 87 | def specificTypes = mimes.findAll { it.name ==~ /\S+?\+xml$/ } | |
| 88 | def appXmlIndex = mimes.indexOf(appXml) | |
| 89 | def appXmlQuality = appXml.parameters.q.toBigDecimal() | |
| 90 | for(mime in specificTypes) { | |
| 91 | if(mime.parameters.q.toBigDecimal() < appXmlQuality) continue | |
| 92 | ||
| 93 | def mimeIndex = mimes.indexOf(mime) | |
| 94 | if(mimeIndex > appXmlIndex) { | |
| 95 | mimes.remove(mime) | |
| 96 | mimes.add(appXmlIndex, mime) | |
| 97 | } | |
| 98 | } | |
| 99 | } | |
| 100 | return mimes.sort(new QualityComparator()) as MimeType[] | |
| 68 | 101 | } |
| 69 | 102 | |
| 70 | 103 | private createMimeTypeAndAddToList(name, mimeConfig, mimes, params = null) { |
| ... | ...@@ -81,5 +114,15 @@ | |
| 81 | 114 | } |
| 82 | 115 | } |
| 83 | 116 | |
| 117 | } | |
| 118 | class QualityComparator implements Comparator { | |
| 119 | ||
| 120 | public int compare(Object t, Object t1) { | |
| 121 | def left = t.parameters.q.toBigDecimal() | |
| 122 | def right = t1.parameters.q.toBigDecimal() | |
| 123 | if(left > right) return -1 | |
| 124 | else if(left < right ) return 1 | |
| 125 | return 0; | |
| 126 | } | |
| 84 | 127 | |
| 85 | 128 | } |
| 86 | 129 | \ No newline at end of file |