function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
alexbalexb 

Ajax Tookit on Custom Button from detail page to update that custom object

I'm want to write some JS in a custom button to update the status field of the current object. I found some example code that seems to do what I want, but I'm getting an error when performing the update.

 

http://pastebin.com/MQdFdFde

 

The error I'm getting is: Refused to set unsafe header "User-Agent"

I get this error when I try to update SF with result = sforce.connection.update(updateRecords);

 

Any tips?

Best Answer chosen by Admin (Salesforce Developers) 
alexbalexb

I solved the problem.

 

I guess there were two bugs in this issue:

1) This bug in the Ajax Toolkit. It was an incidental discovery because it was the only error that was reported to me.

2) I was attempting to clear the field value by doing: (a.Taken_By__c = ""; //an empty string, no spaces), This does nothing. By adding a space to that field value, (a.Taken_By__c = " ";), the intent is understood when received by the SF service, and the field will be cleared, thereby solving my initial problem.

 

The spec-offending code still resides in the Ajax Toolkit, however, and this is a bad thing. I would guess that everyone that uses the Ajax Toolkit DOES receive this error, but because the request is sent anyways (though it probably should not), thereby delivering the expected results, so nobody bothers to investigate the error.

When the request does have the User-Agent a header, the request is violating the specification, so why does the browser still send the request? This is what confuses me now.

All Answers

Rahul SharmaRahul Sharma

Hi Alex,

This code is to update a field of current record.

 

Example:

{!REQUIRESCRIPT("/soap/ajax/20.0/connection.js")}		
//	Required field to perform DML and Query operation in Javascript					
/*	Start creating object	*/
var a = new sforce.SObject("Account");				
//	Initialize Account Object
a.Id = "{!Account.Id}";							//	Giving Id of Current Account to the object
a.Phone = 123456;							//	Updating Any field (This can Be dynamic), we can specify look-up field's here.
/*	Stop creating object	*/

sforce.connection.update([a]);				
//	Update Records in the array to database
location.reload(true);							//	Reloading the page

 Hope it helps.

alexbalexb

No, this gives the same result as my own code. I'm pretty sure the problem lies in the headers on the HttpRequest. There is a header (User-Agent) that the browser sees, so the browser won't send it. 

 

Does anyone know how to set the Request headers in the Ajax Toolkit? I'd like to clear out the User-Agent header.

Rahul SharmaRahul Sharma

Post your code which gives you the same error.

alexbalexb
{!REQUIRESCRIPT("/soap/ajax/20.0/connection.js")}		
//	Required field to perform DML and Query operation in Javascript					
/*	Start creating object	*/
var a = new sforce.SObject("Feature__c");				
//	Initialize Account Object
a.Id = "{!Feature__c.Id}";							//	Giving Id of Current Account to the object
a.Taken_By__c = "";							//	Updating Any field (This can Be dynamic), we can specify look-up field's here.
/*	Stop creating object	*/
console.dir(sforce);
sforce.connection.update([a]);				
//	Update Records in the array to database
//location.reload(true);							//	Reloading the page

 

The error happens here: sforce.connection.update([a]); 

 

Rahul SharmaRahul Sharma

Remove below line and check again:

console.dir(sforce); 
alexbalexb

Same error:

Refused to set unsafe header "User-Agent"

 

I'm in the Chrome browser, by the way.

alexbalexb

Read this: 

http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#dom-xmlhttprequest-setrequestheader

 

The spec for XmlHttpRequest says that the User-Agent can not be set.

 

Now check out the source code from the Ajax Toolkit:

 

this.connection.open("POST", this.url, async);
this.connection.setRequestHeader("Content-Type", "text/xml; charset=UTF-8");
this.connection.setRequestHeader("SOAPAction", "\"\"");
this.connection.setRequestHeader("Accept", "text/xml");
this.connection.setRequestHeader("User-Agent", "SFAJAX 1.0");
this.connection.send(envelope);

 Line 599: they set the User-Agent. (-_-)

 

This is a bug. I found the problem. The creator needs to fix this. I tried contacting SF through support, but they tried to tell me that they don't support the Ajax Toolkit.

I would clear the header before sending it, but I'm pretty sure it is not possible. (or can you remove headers from an XmlHttpRequest?)

 

Can anyone tell me who I can talk to to get this fixed?

sherodsherod

I thought I'd paste this here for the assistance of others.

 

You can eliminate the error by overriding the sforce.Transport function at runtime ('monkey patching').   See below:

 

 

<apex:page >
          <script src="../../soap/ajax/22.0/connection.js" type="text/javascript"></script>
          <script>
sforce.Transport = function(url) {
    this.url = url;
    this.connection = null;

    this.newConnection = function() {
        try {
            this.connection = new ActiveXObject('Msxml2.XMLHTTP');
        } catch(e) {
            try {
                this.connection = new ActiveXObject('Microsoft.XMLHTTP');
            } catch(e) {
                this.connection = new XMLHttpRequest();
            }
        }

        return this.connection;
    };

    this.send = function (envelope, callback, async, timeout) {
        this.newConnection();
        if (async) {
            this.connection.onreadystatechange = this.httpConnectionCallback;
        }
        var holder = new sforce.internal.ConnectionHolder(this.connection, callback);
        sforce.internal._connections.push(holder);
        this.connection.open("POST", this.url, async);
        this.connection.setRequestHeader("Content-Type", "text/xml; charset=UTF-8");
        this.connection.setRequestHeader("SOAPAction", "\"\"");
        this.connection.setRequestHeader("Accept", "text/xml");
     //   this.connection.setRequestHeader("User-Agent", "SFAJAX 1.0");
        this.connection.send(envelope);
        if (async && typeof(timeout) !== "undefined") {
            this.setTimeoutOn(holder, timeout);
        }
        if (!async) {
            this.httpConnectionCallback();
        }
    };

    this.setTimeoutOn = function (holder, timeout) {
        function abortConnection() {
            if (holder.connection.readyState !== 4) {
                holder.timedout = true;
                holder.connection.abort();
            }
        }
        setTimeout(abortConnection, timeout);
    };

    this.httpConnectionCallback = function () {

        for (var i = 0; i < sforce.internal._connections.length; i++) {
            var holder = sforce.internal._connections[i];
            if (holder !== null) {
                if (holder.timedout) {
                    sforce.internal._connections[i] = null;
                    sforce.internal._connections.slice(i,1);
                    holder.callback.httpCallback("Remote invocation timed out", false);
                } else  if (holder.connection.readyState == 4) {
                    sforce.internal._connections[i] = null;
                    sforce.internal._connections.slice(i,1);
                    var success = holder.connection.status == 200;
                    if (sforce.debug.trace) {
                        sforce.debug.log("Response : status - " + holder.connection.status);
                        sforce.debug.logXml(holder.connection.responseText);
                    }
                    if (sforce.debug.apexTrace) {
                        sforce.debug.logApex(holder.connection.responseText);
                    }
                    if (holder.connection.responseXML && holder.connection.responseXML.documentElement) {
                        holder.callback.httpCallback(holder.connection.responseXML.documentElement, success);
                    } else {
                        holder.callback.httpCallback("Remote invocation failed, due to: " + holder.connection.responseText +
                                                     " status code: ", holder.connection.status);
                    }
                }
            }
        }
    };
};
</script>
  <script>
   sforce.connection.login("xxxx", "xxxx");
  result = sforce.connection.query("Select Name, Id from User");
  records = result.getArray("records");
 
  for (var i=0; i< records.length; i++) {
    var record = records[i];
    alert(record.Name + " -- " + record.Id);
  }
</script>
</apex:page>

 

alexbalexb

I solved the problem.

 

I guess there were two bugs in this issue:

1) This bug in the Ajax Toolkit. It was an incidental discovery because it was the only error that was reported to me.

2) I was attempting to clear the field value by doing: (a.Taken_By__c = ""; //an empty string, no spaces), This does nothing. By adding a space to that field value, (a.Taken_By__c = " ";), the intent is understood when received by the SF service, and the field will be cleared, thereby solving my initial problem.

 

The spec-offending code still resides in the Ajax Toolkit, however, and this is a bad thing. I would guess that everyone that uses the Ajax Toolkit DOES receive this error, but because the request is sent anyways (though it probably should not), thereby delivering the expected results, so nobody bothers to investigate the error.

When the request does have the User-Agent a header, the request is violating the specification, so why does the browser still send the request? This is what confuses me now.

This was selected as the best answer
germaine-tgermaine-t

Alex - I have also been running into this exact issue on Chrome.

 

For me however, the request returns a 500 error from the serverUrl.

 

from monitoring the requests, I see that

serverUrl = "https://na12-api.salesforce.com/services/Soap/m/22.0/00DU0000000IEvm" as given by login(), which looks okay to me

 

The odd thing is that the response to this is a 500 error! I thought it might have to do with that user-agent error, but commenting it out makes no difference.

 

Any insight you can still remember from this issue? Any clue why the url returned by login() would give a 500 error?

 

Thank you very much in advance.

 

alexbalexb

Can you post the JS code that you are using? It's probably that the problem lies there.

I can imagine that you are using a Database.update(someObject), but 'someObject' doesn't have a value in the Id property. Another issue could be that you are trying to update 'someObject', but the Id doesn't match that object type.

germaine-tgermaine-t

My code is running in a non-salesforce context that allows for XHR (it's a chrome extension, running on the background page where XHRs are allowed by the browser)

 

var conn = new sforce.Connection(); //this works

 

conn.login("tal@ecquire.com", "password+token"); //this works and returns session id, serverUrl etc etc                

 

var result = sforce.connection.query("Select Name,Id from User", {onSuccess : success, onFailure : failure});

// This is where the problem is caused - the failure callback prints the error below starting with "an error has occurred"

 

I just realized that this is probably a session id issue. In the chrome console these two errors go together (the first is chrome's error reporting):

 



Failed to load resource: the server responded with a status of 500 (Internal Server Error)

 

 

and my failure callback prints out this error object:

 

An error has occurred {faultcode:'sf:INVALID_SESSION_ID', faultstring:'INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session', detail:{UnexpectedErrorFault:{exceptionCode:'INVALID_SESSION_ID', exceptionMessage:'Invalid Session ID found in SessionHeader: Illegal Session', }, }, }

 

 

So it appears that the 500 error is caused by the invalid session id. It's very odd - i'm trying to figure out why that is. Any clue so far? I will continue to investigate and post any new developments.

 


germaine-tgermaine-t

Okay - solved the problem with a "monkey patch"

 

The issue was that for some reason, even though login() returned a sessionId, it was not storing it correctly. Inside sforce.Connection.prototype.login() the line of code this.sessionId = result.sessionId; was not enough to do it.

 

Basically had to copy version 22.0 of the salesforce ajax toolkit, use it locally, and add this more explicit line

 

sforce.connection.sessionId = result.sessionId

 

to this function

 

sforce.Connection.prototype.login()

 

after this line

 

var result = this.invoke("login", [arg1, arg2], false, null);

 

I know it's not the best way to do things since it assumes the instance of the class sforce.Connection, sforce.connection, will always be there, and I hope there's a better solution using the this keyword, but it works for now.

SPMSPM

Hi Rahul,

 

Can you please give an example of code how to set this field value dynamically?

 

Sachin

jungleeejungleee

Hi Steven,

 

The monkey patching script you have provided works like a charm.. Thanks!!

Could you please explain as to what the script does??

 

Regards
Sam

AnandAgrawalAnandAgrawal

Good job Steven, it worked just fine!! Thanks a lot!! :)

 

  

 --

Best Regards,

 

Anand Agrawal
Salesforce Consultant | Horicent Systems | Pune - India

+91.997.028.2098 Skype: horicent.systems Twitter @horicentweets
W www.horicent.com

Ravikant kediaRavikant kedia
Hi germaine-t,
                    I want the code for Javascript that is used to connect salesforce i am making chrome extension. Please give me code for retrive information from salesforce.
Chetan BhavsarChetan Bhavsar
Sometimes the session ID isn't set correctly, so you have to set it yourself.
sforce.connection.sessionId = "{!$Api.Session_ID}";