Skip to content

Commit

Permalink
Support cookies on Android
Browse files Browse the repository at this point in the history
Summary: This adds a persistent cookie store that shares cookies with WebView.

Add a `ForwardingCookieHandler` to OkHttp that uses the underlying Android webkit `CookieManager`.
Use a `LazyCookieHandler` to defer initialization of `CookieManager` as this will in turn trigger initialization of the Chromium stack in KitKat+ which takes some time. This was we will incur this cost on a background network thread instead of during startup.
Also add a `clearCookies()` method to the network module.

Add a cookies example to the XHR example. This example should also work for iOS (except for the clear cookies part). They are for now just scoped to Android.

Closes #2792.

public

Reviewed By: andreicoman11

Differential Revision: D2615550

fb-gh-sync-id: ff726a35f0fc3c7124d2f755448fe24c9d1caf21
  • Loading branch information
lexs authored and facebook-github-bot-6 committed Nov 23, 2015
1 parent f57c2a9 commit 274c5c7
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 15 deletions.
7 changes: 7 additions & 0 deletions Examples/UIExplorer/XHRExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var {
} = React;

var XHRExampleHeaders = require('./XHRExampleHeaders');
var XHRExampleCookies = require('./XHRExampleCookies');


// TODO t7093728 This is a simlified XHRExample.ios.js.
// Once we have Camera roll, Toast, Intent (for opening URLs)
Expand Down Expand Up @@ -284,6 +286,11 @@ exports.examples = [{
render() {
return <XHRExampleHeaders/>;
}
}, {
title: 'Cookies',
render() {
return <XHRExampleCookies/>;
}
}];

var styles = StyleSheet.create({
Expand Down
128 changes: 128 additions & 0 deletions Examples/UIExplorer/XHRExampleCookies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @flow
*/
'use strict';

var React = require('react-native');
var {
StyleSheet,
Text,
TouchableHighlight,
View,
} = React;

var RCTNetworking = require('RCTNetworking');

class XHRExampleCookies extends React.Component {
constructor(props: any) {
super(props);
this.cancelled = false;
this.state = {
status: '',
a: 1,
b: 2,
};
}

setCookie(domain: string) {
var {a, b} = this.state;
var url = `https://${domain}/cookies/set?a=${a}&b=${b}`;
fetch(url).then((response) => {
this.setStatus(`Cookies a=${a}, b=${b} set`);
});

this.setState({
status: 'Setting cookies...',
a: a + 1,
b: b + 2,
});
}

getCookies(domain: string) {
fetch(`https://${domain}/cookies`).then((response) => {
return response.json();
}).then((data) => {
this.setStatus(`Got cookies ${JSON.stringify(data.cookies)} from server`);
});

this.setStatus('Getting cookies...');
}

clearCookies() {
RCTNetworking.clearCookies((cleared) => {
this.setStatus('Cookies cleared, had cookies=' + cleared);
});
}

setStatus(status: string) {
this.setState({status});
}

render() {
return (
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={this.setCookie.bind(this, 'httpbin.org')}>
<View style={styles.button}>
<Text>Set cookie</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.setCookie.bind(this, 'eu.httpbin.org')}>
<View style={styles.button}>
<Text>Set cookie (EU)</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.getCookies.bind(this, 'httpbin.org')}>
<View style={styles.button}>
<Text>Get cookies</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.getCookies.bind(this, 'eu.httpbin.org')}>
<View style={styles.button}>
<Text>Get cookies (EU)</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.clearCookies.bind(this)}>
<View style={styles.button}>
<Text>Clear cookies</Text>
</View>
</TouchableHighlight>
<Text>{this.state.status}</Text>
</View>
);
}
}

var styles = StyleSheet.create({
wrapper: {
borderRadius: 5,
marginBottom: 5,
},
button: {
backgroundColor: '#eeeeee',
padding: 8,
},
});

module.exports = XHRExampleCookies;
4 changes: 4 additions & 0 deletions Libraries/Network/RCTNetworking.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class RCTNetworking {
static abortRequest(requestId) {
RCTNetworkingNative.abortRequest(requestId);
}

static clearCookies(callback) {
RCTNetworkingNative.clearCookies(callback);
}
}

module.exports = RCTNetworking;
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ public void loadLibrary(String libraryName) {
}

Context context = this.getReactApplicationContext().getApplicationContext();
OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
OkHttpClient okHttpClient =
OkHttpClientProvider.getCookieAwareOkHttpClient(getReactApplicationContext());
ImagePipelineConfig.Builder builder =
OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);

Expand Down
Loading

2 comments on commit 274c5c7

@skv-headless
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thanks 👍

@iiitmahesh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skv-headless How to acess cookies during fetch???

Please sign in to comment.