iOS9.3のSafariでiframeにリファラが送られない問題

タイトルの通りですけど、iOS9.3でiframeにリファラが送られないケースがあるみたいです。
どうやらクロスオリジンリクエストの際に起こるようですが、何度か試行してるとたまに送られるケースもあって謎。

全然報告が見当たらないのでみんな再現してないのかなー困るケースないのかなーと思ったりしてたんですけど、今日改めて調べてみたらバグ報告が上がってました。

Overview:
Safari seems to no longer send a Referer header when loading a page through an iframe in some situations. I'm still trying to isolate the exact cause, but it seems to happen reliably when an external reference, such as a javascript file or css file, is loaded in the document head. Also, the Accept header seems to switch to */* instead of text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

https://bugs.webkit.org/show_bug.cgi?id=155754

バージョンアップで早々に対応してくれるとよいですけど、まだBugzillaのStatusがNEWなのでどうなるやら…。

【2016/4/1追記】
FIXEDになってました
Bug 155754 – REGRESSION (r191180): Safari does not send Referer Header to iframe src in certain situations

構文エラーを起こすHTMLをjsoupで綺麗にする

はい。
半年以上ぶりです。

信頼できないユーザーの入力タグをどうすれば楽にきれいに出来るか考えてみたりしてました。
ある程度まともな動きをしてくれそうなものがあったのでメモを兼ねて。

以前にも書いたjsoupでやってみます。

jsoupでHTMLをパースする - するめとめがね

コードは以下のような感じ。

String str = "<div><a href=\"#1\">aaa<a href=\"#2\">bbb</div></div></div>";
Document doc = Jsoup.parseBodyFragment(str);
doc.outputSettings().prettyPrint(false);
System.out.println(doc.body().html());

prettyPrintってやつはデフォルトtrueなんですが、これがtrueだとhtmlメソッドを使ってStringにしたとき、インデントやら改行やら素敵な感じでやってくれちゃうんですが、今回全く求めてないので問答無用でfalseにします。

結果

<div>
 <a href="#1">aaa</a>
 <a href="#2">bbb</a>
</div>

※prettyPrintがfalseになってるので実際は整形されないんですが、わかりづらいのでtrueの状態を書いてます。

うむ。
割といい感じにきれいになったんじゃないでしょうか。

次に以下で試してみます。

<div><a href="#1">aaa<div><a href="#2">bbb</div>

結果

<div>
 <a href="#1">aaa</a>
 <div>
  <a href="#1"></a>
  <a href="#2">bbb</a>
 </div>
</div>

お、おう。
ちょっと、ちょっと変だな。

そんなかんじで意地悪しすぎるとちょっと想定外の挙動をしますが、ある程度の良識あるちょっと間違っちゃったてへぺろ程度のコードであれば割とよろしくやってくれそうです。べんりですね。

MavenでSpringを含む依存jarごと一つのjarにするときハマった件

タイトルが長い。

さらに詳しく言うなら、
MavenでSpringを含む依存jarごと一つのjarにしてインターネットに出られないサーバでそのjarを実行したときハマった件
です。

まず前提として、Springさんはクラスパス内にapplicationContext.xmlとかで定義したxsdファイルが見つからない場合、そのURLを見に行ってパースするようです。
このxsdファイルは、例えば「http://www.springframework.org/schema/beans/spring-beans-4.0.xsd」で言うと、spring-beans-xxx.jarの中のMETA-INF/spring.schemasの中で

http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
http\://www.springframework.org/schema/beans/spring-beans-4.0.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsd

のように記載されており、ここにある通り、その実体は同じくspring-beans-xxx.jarの中のorg.springframework.beans.factory.xmlパッケージの中に存在しています。

次に、依存jarごと一つのjarにまとめる場合、よく使うのはmaven-assembly-pluginです。
ということで実際にmaven-assembly-pluginでjarを作って、インターネットに出られないサーバで実行してみます。

WARN  org.springframework.util.xml.SimpleSaxErrorHandler:48 - Ignored XML validation warning
org.xml.sax.SAXParseException: schema_reference.4: 1)ドキュメントが見つからなかった、2)ドキュメントを読み取れなかった、3)ドキュメントのルート要素が<xsd:schema>ではなかったため、スキーマ・ドキュメント'http://www.springframework.org/schema/beans/spring-beans-4.0.xsd'の読取りに失敗しました。

_人人 人人_
> 突然の死 <
 ̄Y^Y^Y^Y ̄

なんぞこれーということでちょっとjarを展開してみます。
META-INFの下にはspring.schemasがありましたが、中身を見てみるとspring-beansの記述が無く、
spring-contextなどの記述がある状態。
いくつかのSpringのjarに依存していたので、どうやらそれぞれのspring.schemasが上書きに次ぐ上書きを繰り返し、最後に上書きされたやつが成果物に含まれている模様。
というわけで色々調べていると、「maven-shade-plugin」というプラグインならうまいこと出来るみたいなので、maven-assembly-pluginの部分と置き換えてみます。

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-shade-plugin</artifactId>
	<version>2.2</version>
	<configuration>
		<finalName>shade-sample</finalName>
		<transformers>
			<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
				<mainClass>com.tm8r.ShadeTest</mainClass>
			</transformer>
			<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
				<resource>META-INF/spring.handlers</resource>
			</transformer>
			<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
				<resource>META-INF/spring.schemas</resource>
			</transformer>
		</transformers>
	</configuration>
	<executions>
		<execution>
  			<phase>package</phase>
			<goals>
			  <goal>shade</goal>
			</goals>
		</execution>
	</executions>
</plugin>

こんな感じ。
「org.apache.maven.plugins.shade.resource.AppendingTransformer」を指定したtransformerを定義してやると、resourceに指定したファイルが複数あったとき、そのファイルに追記をしていくような挙動をしてくれる模様。

というわけでこれでpackageを実行してやると、spring.schemasとspring.handlersに対して、依存jarに含まれる同名ファイルの内容が全て記述されたものが成果物に含まれる形になりました。
めでたしめでたし。

GuavaのSetsでSetの差分をとったりする

えー今更Guava-?キモーイ!Guavaの記事が許されるのは2012年までだよねー!キャハハハ!
みたいな反応が無いかgkbrしながらも、ちょっといじる機会があったので。
いやGuava全然まだ開発されてるんですけども。

AとBのSetがあってAにあってBにないもの、BにあってAにないものを抽出したい、そんなとき使えるのがSetsのdifferenceメソッドさんです。

Set<String> testSet1 = new HashSet<>();
testSet1.add("a");
testSet1.add("b");
testSet1.add("c");
Set<String> testSet2 = new HashSet<>();
testSet2.add("b");
testSet2.add("c");
testSet2.add("d");
testSet2.add("e");
Set<String> diff1 = Sets.difference(testSet1, testSet2);
Set<String> diff2 = Sets.difference(testSet2, testSet1);

このようにすると、以下のような結果が返ってきます。

diff1:[a]
diff2:[d, e]

べんり!

両方に含まれるものを抽出する場合はintersectionメソッドさんを使います。

Set<String> intersection = Sets.intersection(testSet1, testSet2);

結果は以下の通り。

intersection:[b, c]

捗る。やっぱりGuavaさんすてき。

Ansibleのtips的なあれやそれ

Ansibleをごにょごにょしたので覚え書き程度に。

シンボリックリンクをはる

/usr/local/destに対して/usr/local/srcのシンボリックリンクをはる場合、以下のようにします。

- name: create symlink
  action: file src=/usr/local/src dest=/usr/local/dest state=link

Ansible実行サーバからリモートサーバにrsyncする

1.3.xまではlocal_actionを用いてrsyncコマンドを実行する感じでしたが、
1.4.xからはsynchronizeというモジュールが追加されたのでこれで実現できるみたいです。
rsync_pathはrootで実行したいとか、別のユーザーで実行したいといった場合は以下のように指定してあげるとよいみたいです。

- name: sync files
  action: synchronize src=/usr/local/src dest=/usr/local/dest recursive=yes rsync_path='sudo rsync'

同一コマンドを複数のファイルに対して行う

with_itemsを使えばらくちんです。
{{ item }}と書いた部分に対してwith_itemsで指定したファイルが入ります。

- name: change permission
  action: file path={{ item }} owner=tm8r group=tm8r state=directory recurse=yes
  with_items:
   - /usr/local/hoge/
   - /usr/local/fuga/

すてきですねAnsible。

HipChatで送信したファイルを消す

HipChat、つかってますか!

最近使い始めたのですけど、人にファイルを送信したくてファイルをD&Dしたらuploading…って出てファッ!?となりました。
どうやらS3に上がるっぽいですね。こわい。

・Files uploaded to HipChat are stored on Amazon's S3 servers.
・All uploaded files are accessible via an obscure URL which is shared with people in the chat when the file is uploaded.
・Users are not required to be logged in to view uploaded files - they are visible to anyone who has the link. (This means the links can be shared easily with anyone you want to be able to view the file).

http://help.hipchat.com/knowledgebase/articles/64477-are-files-uploaded-to-hipchat-secure-private-

URLはランダムで生成されるのでピンポイントで誰のものを見るみたいなことは出来なさそうですが、現状特に認証とかはないみたいなのでちょっと怖い。

ので削除する方法を探したところ、ブラウザから消せるっぽいです。
How do I delete chat history and files? – Help Center

ルームでアップロードしたファイルを消す場合は以下、
https://www.hipchat.com/rooms
1:1でアップロードしたファイルを消す場合は以下
https://www.hipchat.com/people
にアクセスし、表示されたヒストリーで該当のファイルの行をマウスオーバーすると「×」マークが出るので、これを選択すると削除できます。

わかりづらい。

tomcatで一つのアプリを複数のバーチャルホストで配信する

普通こんなことしないとは思うんですけど。

tomcatにアプリを二つ以上乗っけて、かつ一方のアプリは複数のドメインで配信する方法です。

たとえば、tm8r.jpはwebbappsにあるアプリが処理、
tm8r.com、tm8rhoge.com、tm8rfuga.comはwebapps2にあるアプリが処理したい場合。

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
</Host>
<Host name="tm8r.com" appBase="webapps2"
unpackWARs="true" autoDeploy="false">
  <Alias>tm8rhoge.com</Alias>
  <Alias>tm8rfuga.com</Alias>
</Host>

こんな感じでAliasを定義してやれば実現出来るもよう。
はじめてつかった。

tm8r.jpは明示的に定義されてないのでlocalhostの設定を参照し、
それ以外の明示的に指定されているドメインはtm8r.comの方を参照します。

tm8rhoge.comとtm8rfuga.comをそれぞれHostに書いてappBaseにwebapp2を指定しても実現できるっちゃできるんですが、書いた分だけアプリがデプロイされてしまうのでこんな感じに。
もっといい方法あったりするのだろうか。とりあえず実現できたのでよいとする。

スポンサーリンク