<div dir="ltr">Hi Sven,<div><br></div><div style>you are right. Seaside needs it as a string. But I&#39;ve found another problem with output (maybe because Seaside uses string???) which leads to error &#39;Improper store into indexable object&#39;.</div>
<div style><br></div><div style>I have JSON on output. It is again string and there is this problem. In ZnZincServerAdaptor&gt;&gt;responseFrom: we are asking for contents.</div><div style><br></div><div style><div><font face="courier new, monospace">ZnZincServerAdaptor&gt;&gt;responseFrom: aRequestContext</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>| partialHeaders cookies fullHeaders seasideResponse contents entity contentType |</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>seasideResponse := aRequestContext response.</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>partialHeaders := seasideResponse headers.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>cookies := seasideResponse cookies.</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>fullHeaders := ZnHeaders defaultResponseHeaders.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>partialHeaders keysAndValuesDo: [ :key :value |</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>fullHeaders at: key put: value ].</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>cookies do: [ :each |</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>fullHeaders at: &#39;Set-Cookie&#39; add: each oldNetscapeString.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>fullHeaders at: &#39;Set-Cookie2&#39; add: each rfc2965String ].</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>contentType := seasideResponse contentType greaseString.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>contents := seasideResponse contents. &quot;&lt;------------------------ HERE - we are asking for contents&quot;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>entity := (ZnEntity bytes: contents) contentType: contentType; yourself.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>^ ZnResponse new</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>statusLine: (ZnStatusLine code: seasideResponse status);</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>headers: fullHeaders;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>entity: entity;</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>yourself</font></div>
<div><br></div><div style>It calls:</div><div style><br></div><div style><div><font face="courier new, monospace">WABufferedResponse&gt;&gt;contents</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>^ contentsStream contents &quot;&lt;------------------------ HERE - normally, asking underlying stream for contents&quot;</font></div>
<div><br></div><div style>An the error is coming here:</div><div style><br></div><div style><div><font face="courier new, monospace">RWBinaryOrTextStream&gt;&gt;contents</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&quot;Answer with a copy of my collection from 1 to readLimit.&quot;</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>| newArray |</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>isBinary ifFalse: [^ super contents].<span class="" style="white-space:pre">        </span>&quot;String&quot;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>readLimit := readLimit max: position.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>newArray := ByteArray new: readLimit. &quot;&lt;------------------------ HERE - we are creating array of bytes (SmallInteger 0 - 255)&quot;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>^ newArray replaceFrom: 1</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>to: readLimit</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>with: collection  &quot;&lt;------------------------ HERE - but we are having WideString in collection - characters&quot;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>startingAt: 1.</font></div><div><br></div><div style>Now we are calling primitive 105:</div><div style><br></div><div style><div><font face="courier new, monospace">ByteArray&gt;&gt;replaceFrom: start to: stop with: replacement startingAt: repStart </font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&quot;Primitive. This destructively replaces elements from start to stop in the receiver starting at index, repStart, in the collection, replacement. Answer the receiver. Range checks are performed in the primitive only. Optional. See Object documentation whatIsAPrimitive.&quot;</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&lt;primitive: 105&gt;</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>super replaceFrom: start to: stop with: replacement startingAt: repStart &quot;&lt;------------------------ HERE - it fails and continues here&quot;</font></div>
<div><br></div><div style>It calls loop in SequenceableCollection:</div><div style><br></div><div style><div><font face="courier new, monospace">ByteArray(SequenceableCollection)&gt;&gt;replaceFrom: start to: stop with: replacement startingAt: repStart </font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&quot;This destructively replaces elements from start to stop in the receiver </font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>starting at index, repStart, in the sequenceable collection, </font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>replacementCollection. Answer the receiver. No range checks are </font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>performed.&quot;</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>| index repOff |</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>repOff := repStart - start.</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>index := start - 1.</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>[(index := index + 1) &lt;= stop]</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>whileTrue: [self at: index put: (replacement at: repOff + index)] &quot;&lt;------------------------ HERE - here we are putting character into ByteArray&quot;</font></div>
<div><br></div><div style>Stops here at Object at primitive 61:</div><div style><br></div><div style><div><font face="courier new, monospace">ByteArray(Object)&gt;&gt;at: index put: value </font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&quot;Primitive. Assumes receiver is indexable. Store the argument value in </font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>the indexable element of the receiver indicated by index. Fail if the </font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>index is not an Integer or is out of bounds. Or fail if the value is not of </font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>the right type for this kind of collection. Answer the value that was </font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>stored. Essential. See Object documentation whatIsAPrimitive.&quot;</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>&lt;primitive: 61&gt;</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>index isInteger ifTrue:</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>[self class isVariable</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                        </span>ifTrue: [(index &gt;= 1 and: [index &lt;= self size])</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                                        </span>ifTrue: [self errorImproperStore] &quot;&lt;------------------------ HERE - ends here&quot;</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                                        </span>ifFalse: [self errorSubscriptBounds: index]]</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                        </span>ifFalse: [self errorNotIndexable]].</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">        </span>index isNumber</font></div>
<div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>ifTrue: [^self at: index asInteger put: value]</font></div><div><font face="courier new, monospace"><span class="" style="white-space:pre">                </span>ifFalse: [self errorNonIntegerIndex]</font></div>
<div><font face="courier new, monospace"><br></font></div><div style><font face="arial, helvetica, sans-serif">I&#39;ve seen this problem mostly with Seaside-REST, but also in some other posts from Seaside.</font></div><div style>
<font face="arial, helvetica, sans-serif"><br></font></div><div style><font face="arial, helvetica, sans-serif">Any idea how to fix it?</font></div><div style><font face="arial, helvetica, sans-serif"><br></font></div><div style>
<font face="arial, helvetica, sans-serif">Regards,</font></div><div style><font face="arial, helvetica, sans-serif">Tomas</font></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">
On Wed, Jun 26, 2013 at 12:17 AM, Sven Van Caekenberghe <span dir="ltr">&lt;<a href="mailto:sven@stfx.eu" target="_blank">sven@stfx.eu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Tomas,<br>
<br>
Thanks for the report: this is an important area indeed.<br>
<br>
However, the comment says it: this is intentional, and as far as I know, it is correct. You see, Zinc will correctly decode/encode any HTTP payload, using the supplied mime-type and/or charsets. Seaside is written such that it does not want this: it insists on doing this on its own. That is why ZnZincServerAdaptor is _not_ using the normal request reading code of Zn, but uses a special option to read everything binary. The stupid thing is that even though Seaside needs bytes, it wants them as a String. That is the reason for the otherwise brain dead #asString (and the implicit copy is inefficient as well).<br>

<br>
Of course, you will see your special characters there if you do UTF8 decoding, but that is because you already know what is inside.<br>
<br>
What normally happens, is that later on in the processing, Seaside will access the WARequest payload using proper decoding, using its own framework (much like what Zn would do). AFAIK this whole process works. You can actually test this using some of the functional tests.<br>

<br>
I am not sure that Seaside-REST is doing the right thing (there were some issues with SmalltalkHub as well), but I would think so.<br>
<br>
Are you sure you have set the correct encoding on the adaptor ?<br>
<br>
Are you sure you are posting as application/json;charset=utf-8 and if you do not set the charset, are you sure utf-8 is the default ?<br>
<br>
Are you sure your REST handler and/or JSON parser does the right thing ?<br>
<br>
It is too late right now, but if we want to get further with this, I will need a failing unit test - if these exist in Seaside-REST, but I would assume so. I have no experience running Seaside-REST, I am using Zinc-REST myself, but I would like to learn.<br>

<br>
Regards,<br>
<br>
Sven<br>
<div><div class="h5"><br>
On 25 Jun 2013, at 23:24, Tomas Kukol &lt;<a href="mailto:tomas.kukol@gmail.com">tomas.kukol@gmail.com</a>&gt; wrote:<br>
<br>
&gt; Hi Sven.<br>
&gt;<br>
&gt; I&#39;ve had a problem when POSTing non-ascii UTF-8 characters in JSON to Seaside REST service. I&#39;ve located the problem in the method ZnZincServerAdaptor&gt;&gt;requestBodyFor: where the body of ZnRequest is translated to body of WARequest. I use Pharo 1.4 with Seaside 3.0.8 and Zinc-Seaside-SvenVanCaekenberghe.40.<br>

&gt;<br>
&gt; When the POSTed JSON contains non-ascii UTF-8 characters (Czech characters), they are corrupted. The problem is on the &quot;MARKED&quot; line, where the array of bytes changed to string by asString.<br>
&gt;<br>
&gt; &quot;Problematic&quot; code:<br>
&gt;<br>
&gt; ZnZincServerAdaptor&gt;&gt;requestBodyFor: aZincRequest<br>
&gt;       ^ (aZincRequest method ~= #TRACE<br>
&gt;               and: [ aZincRequest hasEntity<br>
&gt;                       and: [ aZincRequest entity isEmpty not<br>
&gt;                               and: [ (aZincRequest entity contentType matches: ZnMimeType applicationFormUrlEncoded) not<br>
&gt;                                       and: [ (aZincRequest entity contentType matches: ZnMimeType multiPartFormData) not ] ] ] ])<br>
&gt;                       ifTrue: [<br>
&gt;                               &quot;Seaside wants to do its own text conversions&quot;<br>
&gt;                               aZincRequest entity bytes asString &quot;MARKED&quot; ]<br>
&gt;                       ifFalse: [<br>
&gt;                               String new ]<br>
&gt;<br>
&gt; I did a quick correction, which is not nice, but works for me:<br>
&gt;<br>
&gt; ZnZincServerAdaptor&gt;&gt;requestBodyFor: aZincRequest<br>
&gt;       ^ (aZincRequest method ~= #TRACE<br>
&gt;               and: [ aZincRequest hasEntity<br>
&gt;                       and: [ aZincRequest entity isEmpty not<br>
&gt;                               and: [ (aZincRequest entity contentType matches: ZnMimeType applicationFormUrlEncoded) not<br>
&gt;                                       and: [ (aZincRequest entity contentType matches: ZnMimeType multiPartFormData) not ] ] ] ])<br>
&gt;                       ifTrue: [<br>
&gt;                               &quot;Seaside wants to do its own text conversions&quot;<br>
&gt;                               ZnUTF8Encoder new decodeBytes: aZincRequest entity bytes &quot;CORRECTED&quot; ]<br>
&gt;                       ifFalse: [<br>
&gt;                               String new ]<br>
&gt;<br>
&gt; My correction tries to decode byte array with ZnUTF8Encoder and the result is OK.<br>
&gt;<br>
&gt; Maybe I would recommend to use GRPharoUtf8Codec (although I like ZnUTF8Encoder more) or even better self codec (self = ZnZincServerAdaptor) to try to decode the bytes.<br>
&gt;<br>
&gt; Regards,<br>
&gt; Tomas Kukol<br>
</div></div>&gt; _______________________________________________<br>
&gt; seaside mailing list<br>
&gt; <a href="mailto:seaside@lists.squeakfoundation.org">seaside@lists.squeakfoundation.org</a><br>
&gt; <a href="http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside" target="_blank">http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside</a><br>
<br>
<br>
<br>
--<br>
Sven Van Caekenberghe<br>
<a href="http://stfx.eu" target="_blank">http://stfx.eu</a><br>
Smalltalk is the Red Pill<br>
<br>
_______________________________________________<br>
seaside mailing list<br>
<a href="mailto:seaside@lists.squeakfoundation.org">seaside@lists.squeakfoundation.org</a><br>
<a href="http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside" target="_blank">http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside</a><br>
</blockquote></div><br></div>